From 270ef81a8ebba665c00c98da57f9d65dc08f3d1b Mon Sep 17 00:00:00 2001
From: Marko Ivancic <marko.ivancic@srce.hr>
Date: Tue, 22 Nov 2022 15:45:24 +0000
Subject: [PATCH] Relate histories

---
 .gitignore                                    |    4 +
 LICENSE                                       |  504 ++
 README.md                                     |  164 +-
 bin/test.php                                  |  140 +
 composer.json                                 |   54 +
 composer.lock                                 | 7776 +++++++++++++++++
 config-templates/module_accounting.php        |  206 +
 hooks/hook_adminmenu.php                      |   30 +
 hooks/hook_configpage.php                     |   26 +
 hooks/hook_cron.php                           |   91 +
 locales/en/LC_MESSAGES/accounting.po          |   18 +
 phpcs.xml                                     |   17 +
 phpunit.xml                                   |   42 +
 psalm.xml                                     |   41 +
 routing/routes/routes.yml                     |   28 +
 routing/services/services.yml                 |   19 +
 src/Auth/Process/Accounting.php               |   98 +
 src/Entities/Activity.php                     |   59 +
 src/Entities/Activity/Bag.php                 |   20 +
 src/Entities/Authentication/Event.php         |   29 +
 src/Entities/Authentication/Event/Job.php     |   37 +
 src/Entities/Authentication/State.php         |  198 +
 src/Entities/Bases/AbstractJob.php            |   47 +
 src/Entities/Bases/AbstractPayload.php        |    9 +
 src/Entities/Bases/AbstractProvider.php       |   76 +
 src/Entities/ConnectedServiceProvider.php     |   79 +
 src/Entities/ConnectedServiceProvider/Bag.php |   27 +
 src/Entities/GenericJob.php                   |   13 +
 src/Entities/IdentityProvider.php             |   11 +
 src/Entities/Interfaces/JobInterface.php      |   21 +
 src/Entities/ServiceProvider.php              |   11 +
 src/Entities/User.php                         |   23 +
 src/Exceptions/Exception.php                  |    7 +
 .../InvalidConfigurationException.php         |   11 +
 src/Exceptions/InvalidValueException.php      |   11 +
 src/Exceptions/StoreException.php             |   11 +
 .../StoreException/MigrationException.php     |   11 +
 src/Exceptions/UnexpectedValueException.php   |    9 +
 src/Helpers/ArrayHelper.php                   |   20 +
 src/Helpers/AttributesHelper.php              |   35 +
 src/Helpers/DateTimeHelper.php                |   27 +
 src/Helpers/EnvironmentHelper.php             |   11 +
 src/Helpers/FilesystemHelper.php              |   21 +
 src/Helpers/HashHelper.php                    |   26 +
 ...eBuilderUsingModuleConfigurationHelper.php |   62 +
 src/Helpers/ModuleRoutesHelper.php            |   31 +
 src/Helpers/NetworkHelper.php                 |   32 +
 src/Helpers/RandomHelper.php                  |   19 +
 src/Http/Controllers/Admin/Configuration.php  |  126 +
 src/Http/Controllers/Test.php                 |   75 +
 src/Http/Controllers/User/Profile.php         |  191 +
 ...dableUsingModuleConfigurationInterface.php |   13 +
 src/Interfaces/SetupableInterface.php         |    9 +
 src/ModuleConfiguration.php                   |  488 ++
 .../AccountingProcessingType.php              |   16 +
 src/ModuleConfiguration/ConnectionType.php    |   16 +
 .../AuthenticationDataProviderBuilder.php     |   65 +
 .../AuthenticationDataProviderInterface.php   |   24 +
 src/Services/HelpersManager.php               |   80 +
 src/Services/JobRunner.php                    |  599 ++
 src/Services/JobRunner/RateLimiter.php        |   76 +
 src/Services/JobRunner/State.php              |  202 +
 src/Services/Logger.php                       |   58 +
 src/Stores/Bases/AbstractStore.php            |   64 +
 .../Bases/DoctrineDbal/AbstractRawEntity.php  |   51 +
 .../Bases/DoctrineDbal/AbstractStore.php      |  118 +
 .../Builders/Bases/AbstractStoreBuilder.php   |   65 +
 src/Stores/Builders/DataStoreBuilder.php      |   32 +
 src/Stores/Builders/JobsStoreBuilder.php      |   36 +
 .../Connections/Bases/AbstractMigrator.php    |  140 +
 .../DoctrineDbal/Bases/AbstractMigration.php  |   68 +
 .../Connections/DoctrineDbal/Connection.php   |   60 +
 .../Connections/DoctrineDbal/Factory.php      |   34 +
 .../Connections/DoctrineDbal/Migrator.php     |  182 +
 .../DoctrineDbal/Versioned/Store.php          |  557 ++
 .../Versioned/Store/HashDecoratedState.php    |   84 +
 .../Version20220801000000CreateIdpTable.php   |   69 +
 ...ion20220801000100CreateIdpVersionTable.php |   74 +
 .../Version20220801000200CreateSpTable.php    |   69 +
 ...sion20220801000300CreateSpVersionTable.php |   74 +
 .../Version20220801000400CreateUserTable.php  |   70 +
 ...on20220801000500CreateUserVersionTable.php |   75 +
 ...20801000600CreateIdpSpUserVersionTable.php |   92 +
 ...01000700CreateAuthenticationEventTable.php |   79 +
 .../Versioned/Store/RawActivity.php           |  139 +
 .../Store/RawConnectedServiceProvider.php     |  170 +
 .../Versioned/Store/Repository.php            | 1093 +++
 .../Versioned/Store/TableConstants.php        |  102 +
 src/Stores/Interfaces/ConnectionInterface.php |    9 +
 src/Stores/Interfaces/DataStoreInterface.php  |   29 +
 src/Stores/Interfaces/JobsStoreInterface.php  |   38 +
 src/Stores/Interfaces/MigrationInterface.php  |   22 +
 src/Stores/Interfaces/StoreInterface.php      |   19 +
 src/Stores/Jobs/DoctrineDbal/Store.php        |  153 +
 .../Bases/AbstractCreateJobsTable.php         |   60 +
 .../Version20220601000000CreateJobTable.php   |   15 +
 ...sion20220601000100CreateJobFailedTable.php |   15 +
 src/Stores/Jobs/DoctrineDbal/Store/RawJob.php |  119 +
 .../Jobs/DoctrineDbal/Store/Repository.php    |  194 +
 .../DoctrineDbal/Store/TableConstants.php     |   19 +
 src/Stores/Jobs/PhpRedis/RedisStore.php       |  190 +
 .../DoctrineDbal/Versioned/Tracker.php        |  106 +
 .../AuthenticationDataTrackerBuilder.php      |   60 +
 .../AuthenticationDataTrackerInterface.php    |   21 +
 templates/admin/configuration/status.twig     |   77 +
 templates/base.twig                           |   33 +
 templates/includes/_header.twig               |    6 +
 templates/includes/_navigation.twig           |   40 +
 templates/user/activity.twig                  |   68 +
 templates/user/activity.twig.bak              |   73 +
 templates/user/connected-organizations.twig   |   66 +
 .../user/connected-organizations.twig.bak     |   70 +
 templates/user/personal-data.twig             |   34 +
 templates/user/personal-data.twig.bak         |   35 +
 tests/attributemap/test.php                   |    8 +
 tests/attributemap/test2.php                  |    8 +
 tests/config-templates/config.php             | 1161 +++
 tests/config-templates/module_accounting.php  |   61 +
 tests/src/Auth/Process/AccountingTest.php     |  182 +
 tests/src/Constants/ConnectionParameters.php  |   10 +
 tests/src/Constants/DateTime.php              |   10 +
 tests/src/Constants/RawRowResult.php          |   27 +
 tests/src/Constants/SerializedJob.php         |   12 +
 tests/src/Constants/StateArrays.php           |  134 +
 tests/src/Entities/Activity/BagTest.php       |   26 +
 tests/src/Entities/ActivityTest.php           |   51 +
 .../Entities/Authentication/Event/JobTest.php |   46 +
 .../src/Entities/Authentication/EventTest.php |   32 +
 .../src/Entities/Authentication/StateTest.php |  188 +
 tests/src/Entities/Bases/AbstractJobTest.php  |   40 +
 .../Entities/Bases/AbstractProviderTest.php   |   95 +
 .../ConnectedServiceProvider/BagTest.php      |   23 +
 .../Entities/ConnectedServiceProviderTest.php |   51 +
 tests/src/Entities/GenericJobTest.php         |   21 +
 tests/src/Entities/IdentityProviderTest.php   |   34 +
 tests/src/Entities/ServiceProviderTest.php    |   31 +
 tests/src/Entities/UserTest.php               |   32 +
 tests/src/Helpers/ArrayHelperTest.php         |   31 +
 tests/src/Helpers/AttributesHelperTest.php    |   54 +
 tests/src/Helpers/DateTimeHelperTest.php      |   28 +
 tests/src/Helpers/EnvironmentHelperTest.php   |   19 +
 tests/src/Helpers/FilesystemHelperTest.php    |   31 +
 tests/src/Helpers/HashHelperTest.php          |   63 +
 ...lderUsingModuleConfigurationHelperTest.php |   65 +
 tests/src/Helpers/ModuleRoutesHelperTest.php  |   56 +
 tests/src/Helpers/NetworkHelperTest.php       |   48 +
 tests/src/Helpers/RandomHelperTest.php        |   17 +
 tests/src/ModuleConfigurationTest.php         |  352 +
 .../AuthenticationDataProviderBuilderTest.php |   86 +
 tests/src/Services/HelpersManagerTest.php     |   43 +
 .../Services/JobRunner/RateLimiterTest.php    |   67 +
 tests/src/Services/JobRunner/StateTest.php    |  117 +
 tests/src/Services/JobRunnerTest.php          | 1085 +++
 tests/src/Services/LoggerServiceTest.php      |   31 +
 tests/src/Stores/Bases/AbstractStoreTest.php  |   63 +
 .../DoctrineDbal/AbstractRawEntityTest.php    |   74 +
 .../Stores/Builders/DataStoreBuilderTest.php  |   63 +
 .../Stores/Builders/JobsStoreBuilderTest.php  |  138 +
 .../Bases/AbstractMigratorTest.php            |  185 +
 .../Bases/AbstractMigrationTest.php           |  115 +
 .../DoctrineDbal/ConnectionTest.php           |   55 +
 .../Connections/DoctrineDbal/FactoryTest.php  |   54 +
 .../Connections/DoctrineDbal/MigratorTest.php |  238 +
 .../Store/HashDecoratedStateTest.php          |   71 +
 ...ersion20220801000000CreateIdpTableTest.php |   84 +
 ...0220801000100CreateIdpVersionTableTest.php |   84 +
 ...Version20220801000200CreateSpTableTest.php |   84 +
 ...20220801000300CreateSpVersionTableTest.php |   84 +
 ...rsion20220801000400CreateUserTableTest.php |   84 +
 ...220801000500CreateUserVersionTableTest.php |   84 +
 ...1000600CreateIdpSpUserVersionTableTest.php |   88 +
 ...0700CreateAuthenticationEventTableTest.php |   84 +
 .../Versioned/Store/RawActivityTest.php       |  146 +
 .../Store/RawConnectedServiceProviderTest.php |  177 +
 .../Versioned/Store/RepositoryTest.php        |  789 ++
 .../DoctrineDbal/Versioned/StoreTest.php      |  683 ++
 ...ersion20220601000000CreateJobTableTest.php |   73 +
 ...20220601000100CreateJobFailedTableTest.php |   73 +
 .../Jobs/DoctrineDbal/Store/RawJobTest.php    |  127 +
 .../DoctrineDbal/Store/RepositoryTest.php     |  233 +
 .../Stores/Jobs/DoctrineDbal/StoreTest.php    |  388 +
 .../Stores/Jobs/PhpRedis/RedisStoreTest.php   |  377 +
 .../DoctrineDbal/Versioned/TrackerTest.php    |  216 +
 .../AuthenticationDataTrackerBuilderTest.php  |  111 +
 www/assets/css/src/custom.css                 |   42 +
 www/assets/css/src/default.css                |  424 +
 .../raleway-v28-latin-ext_latin-300.woff      |  Bin 0 -> 38728 bytes
 .../raleway-v28-latin-ext_latin-300.woff2     |  Bin 0 -> 30788 bytes
 .../raleway-v28-latin-ext_latin-500.woff      |  Bin 0 -> 38156 bytes
 .../raleway-v28-latin-ext_latin-500.woff2     |  Bin 0 -> 30184 bytes
 .../raleway-v28-latin-ext_latin-600.woff      |  Bin 0 -> 39596 bytes
 .../raleway-v28-latin-ext_latin-600.woff2     |  Bin 0 -> 31544 bytes
 .../raleway-v28-latin-ext_latin-regular.woff  |  Bin 0 -> 38932 bytes
 .../raleway-v28-latin-ext_latin-regular.woff2 |  Bin 0 -> 30932 bytes
 www/assets/css/src/icons/activity.svg         |    3 +
 www/assets/css/src/icons/conn-orgs.svg        |    3 +
 www/assets/css/src/icons/download.svg         |    4 +
 www/assets/css/src/icons/dropdown.svg         |    3 +
 www/assets/css/src/icons/fppp-logo.svg        |   37 +
 www/assets/css/src/icons/i.svg                |    3 +
 www/assets/css/src/icons/logout.svg           |    3 +
 www/assets/css/src/icons/prof-page.svg        |    3 +
 www/assets/css/src/icons/x.svg                |    3 +
 203 files changed, 27531 insertions(+), 66 deletions(-)
 create mode 100644 .gitignore
 create mode 100644 LICENSE
 create mode 100644 bin/test.php
 create mode 100644 composer.json
 create mode 100644 composer.lock
 create mode 100644 config-templates/module_accounting.php
 create mode 100644 hooks/hook_adminmenu.php
 create mode 100644 hooks/hook_configpage.php
 create mode 100644 hooks/hook_cron.php
 create mode 100644 locales/en/LC_MESSAGES/accounting.po
 create mode 100644 phpcs.xml
 create mode 100644 phpunit.xml
 create mode 100644 psalm.xml
 create mode 100644 routing/routes/routes.yml
 create mode 100644 routing/services/services.yml
 create mode 100644 src/Auth/Process/Accounting.php
 create mode 100644 src/Entities/Activity.php
 create mode 100644 src/Entities/Activity/Bag.php
 create mode 100644 src/Entities/Authentication/Event.php
 create mode 100644 src/Entities/Authentication/Event/Job.php
 create mode 100644 src/Entities/Authentication/State.php
 create mode 100644 src/Entities/Bases/AbstractJob.php
 create mode 100644 src/Entities/Bases/AbstractPayload.php
 create mode 100644 src/Entities/Bases/AbstractProvider.php
 create mode 100644 src/Entities/ConnectedServiceProvider.php
 create mode 100644 src/Entities/ConnectedServiceProvider/Bag.php
 create mode 100644 src/Entities/GenericJob.php
 create mode 100644 src/Entities/IdentityProvider.php
 create mode 100644 src/Entities/Interfaces/JobInterface.php
 create mode 100644 src/Entities/ServiceProvider.php
 create mode 100644 src/Entities/User.php
 create mode 100644 src/Exceptions/Exception.php
 create mode 100644 src/Exceptions/InvalidConfigurationException.php
 create mode 100644 src/Exceptions/InvalidValueException.php
 create mode 100644 src/Exceptions/StoreException.php
 create mode 100644 src/Exceptions/StoreException/MigrationException.php
 create mode 100644 src/Exceptions/UnexpectedValueException.php
 create mode 100644 src/Helpers/ArrayHelper.php
 create mode 100644 src/Helpers/AttributesHelper.php
 create mode 100644 src/Helpers/DateTimeHelper.php
 create mode 100644 src/Helpers/EnvironmentHelper.php
 create mode 100644 src/Helpers/FilesystemHelper.php
 create mode 100644 src/Helpers/HashHelper.php
 create mode 100644 src/Helpers/InstanceBuilderUsingModuleConfigurationHelper.php
 create mode 100644 src/Helpers/ModuleRoutesHelper.php
 create mode 100644 src/Helpers/NetworkHelper.php
 create mode 100644 src/Helpers/RandomHelper.php
 create mode 100644 src/Http/Controllers/Admin/Configuration.php
 create mode 100644 src/Http/Controllers/Test.php
 create mode 100644 src/Http/Controllers/User/Profile.php
 create mode 100644 src/Interfaces/BuildableUsingModuleConfigurationInterface.php
 create mode 100644 src/Interfaces/SetupableInterface.php
 create mode 100644 src/ModuleConfiguration.php
 create mode 100644 src/ModuleConfiguration/AccountingProcessingType.php
 create mode 100644 src/ModuleConfiguration/ConnectionType.php
 create mode 100644 src/Providers/Builders/AuthenticationDataProviderBuilder.php
 create mode 100644 src/Providers/Interfaces/AuthenticationDataProviderInterface.php
 create mode 100644 src/Services/HelpersManager.php
 create mode 100644 src/Services/JobRunner.php
 create mode 100644 src/Services/JobRunner/RateLimiter.php
 create mode 100644 src/Services/JobRunner/State.php
 create mode 100644 src/Services/Logger.php
 create mode 100644 src/Stores/Bases/AbstractStore.php
 create mode 100644 src/Stores/Bases/DoctrineDbal/AbstractRawEntity.php
 create mode 100644 src/Stores/Bases/DoctrineDbal/AbstractStore.php
 create mode 100644 src/Stores/Builders/Bases/AbstractStoreBuilder.php
 create mode 100644 src/Stores/Builders/DataStoreBuilder.php
 create mode 100644 src/Stores/Builders/JobsStoreBuilder.php
 create mode 100644 src/Stores/Connections/Bases/AbstractMigrator.php
 create mode 100644 src/Stores/Connections/DoctrineDbal/Bases/AbstractMigration.php
 create mode 100644 src/Stores/Connections/DoctrineDbal/Connection.php
 create mode 100644 src/Stores/Connections/DoctrineDbal/Factory.php
 create mode 100644 src/Stores/Connections/DoctrineDbal/Migrator.php
 create mode 100644 src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store.php
 create mode 100644 src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/HashDecoratedState.php
 create mode 100644 src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000000CreateIdpTable.php
 create mode 100644 src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000100CreateIdpVersionTable.php
 create mode 100644 src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000200CreateSpTable.php
 create mode 100644 src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000300CreateSpVersionTable.php
 create mode 100644 src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000400CreateUserTable.php
 create mode 100644 src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000500CreateUserVersionTable.php
 create mode 100644 src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000600CreateIdpSpUserVersionTable.php
 create mode 100644 src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000700CreateAuthenticationEventTable.php
 create mode 100644 src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawActivity.php
 create mode 100644 src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawConnectedServiceProvider.php
 create mode 100644 src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Repository.php
 create mode 100644 src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/TableConstants.php
 create mode 100644 src/Stores/Interfaces/ConnectionInterface.php
 create mode 100644 src/Stores/Interfaces/DataStoreInterface.php
 create mode 100644 src/Stores/Interfaces/JobsStoreInterface.php
 create mode 100644 src/Stores/Interfaces/MigrationInterface.php
 create mode 100644 src/Stores/Interfaces/StoreInterface.php
 create mode 100644 src/Stores/Jobs/DoctrineDbal/Store.php
 create mode 100644 src/Stores/Jobs/DoctrineDbal/Store/Migrations/Bases/AbstractCreateJobsTable.php
 create mode 100644 src/Stores/Jobs/DoctrineDbal/Store/Migrations/Version20220601000000CreateJobTable.php
 create mode 100644 src/Stores/Jobs/DoctrineDbal/Store/Migrations/Version20220601000100CreateJobFailedTable.php
 create mode 100644 src/Stores/Jobs/DoctrineDbal/Store/RawJob.php
 create mode 100644 src/Stores/Jobs/DoctrineDbal/Store/Repository.php
 create mode 100644 src/Stores/Jobs/DoctrineDbal/Store/TableConstants.php
 create mode 100644 src/Stores/Jobs/PhpRedis/RedisStore.php
 create mode 100644 src/Trackers/Authentication/DoctrineDbal/Versioned/Tracker.php
 create mode 100644 src/Trackers/Builders/AuthenticationDataTrackerBuilder.php
 create mode 100644 src/Trackers/Interfaces/AuthenticationDataTrackerInterface.php
 create mode 100644 templates/admin/configuration/status.twig
 create mode 100644 templates/base.twig
 create mode 100644 templates/includes/_header.twig
 create mode 100644 templates/includes/_navigation.twig
 create mode 100644 templates/user/activity.twig
 create mode 100644 templates/user/activity.twig.bak
 create mode 100644 templates/user/connected-organizations.twig
 create mode 100644 templates/user/connected-organizations.twig.bak
 create mode 100644 templates/user/personal-data.twig
 create mode 100644 templates/user/personal-data.twig.bak
 create mode 100644 tests/attributemap/test.php
 create mode 100644 tests/attributemap/test2.php
 create mode 100644 tests/config-templates/config.php
 create mode 100644 tests/config-templates/module_accounting.php
 create mode 100644 tests/src/Auth/Process/AccountingTest.php
 create mode 100644 tests/src/Constants/ConnectionParameters.php
 create mode 100644 tests/src/Constants/DateTime.php
 create mode 100644 tests/src/Constants/RawRowResult.php
 create mode 100644 tests/src/Constants/SerializedJob.php
 create mode 100644 tests/src/Constants/StateArrays.php
 create mode 100644 tests/src/Entities/Activity/BagTest.php
 create mode 100644 tests/src/Entities/ActivityTest.php
 create mode 100644 tests/src/Entities/Authentication/Event/JobTest.php
 create mode 100644 tests/src/Entities/Authentication/EventTest.php
 create mode 100644 tests/src/Entities/Authentication/StateTest.php
 create mode 100644 tests/src/Entities/Bases/AbstractJobTest.php
 create mode 100644 tests/src/Entities/Bases/AbstractProviderTest.php
 create mode 100644 tests/src/Entities/ConnectedServiceProvider/BagTest.php
 create mode 100644 tests/src/Entities/ConnectedServiceProviderTest.php
 create mode 100644 tests/src/Entities/GenericJobTest.php
 create mode 100644 tests/src/Entities/IdentityProviderTest.php
 create mode 100644 tests/src/Entities/ServiceProviderTest.php
 create mode 100644 tests/src/Entities/UserTest.php
 create mode 100644 tests/src/Helpers/ArrayHelperTest.php
 create mode 100644 tests/src/Helpers/AttributesHelperTest.php
 create mode 100644 tests/src/Helpers/DateTimeHelperTest.php
 create mode 100644 tests/src/Helpers/EnvironmentHelperTest.php
 create mode 100644 tests/src/Helpers/FilesystemHelperTest.php
 create mode 100644 tests/src/Helpers/HashHelperTest.php
 create mode 100644 tests/src/Helpers/InstanceBuilderUsingModuleConfigurationHelperTest.php
 create mode 100644 tests/src/Helpers/ModuleRoutesHelperTest.php
 create mode 100644 tests/src/Helpers/NetworkHelperTest.php
 create mode 100644 tests/src/Helpers/RandomHelperTest.php
 create mode 100644 tests/src/ModuleConfigurationTest.php
 create mode 100644 tests/src/Providers/Builders/AuthenticationDataProviderBuilderTest.php
 create mode 100644 tests/src/Services/HelpersManagerTest.php
 create mode 100644 tests/src/Services/JobRunner/RateLimiterTest.php
 create mode 100644 tests/src/Services/JobRunner/StateTest.php
 create mode 100644 tests/src/Services/JobRunnerTest.php
 create mode 100644 tests/src/Services/LoggerServiceTest.php
 create mode 100644 tests/src/Stores/Bases/AbstractStoreTest.php
 create mode 100644 tests/src/Stores/Bases/DoctrineDbal/AbstractRawEntityTest.php
 create mode 100644 tests/src/Stores/Builders/DataStoreBuilderTest.php
 create mode 100644 tests/src/Stores/Builders/JobsStoreBuilderTest.php
 create mode 100644 tests/src/Stores/Connections/Bases/AbstractMigratorTest.php
 create mode 100644 tests/src/Stores/Connections/DoctrineDbal/Bases/AbstractMigrationTest.php
 create mode 100644 tests/src/Stores/Connections/DoctrineDbal/ConnectionTest.php
 create mode 100644 tests/src/Stores/Connections/DoctrineDbal/FactoryTest.php
 create mode 100644 tests/src/Stores/Connections/DoctrineDbal/MigratorTest.php
 create mode 100644 tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/HashDecoratedStateTest.php
 create mode 100644 tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000000CreateIdpTableTest.php
 create mode 100644 tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000100CreateIdpVersionTableTest.php
 create mode 100644 tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000200CreateSpTableTest.php
 create mode 100644 tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000300CreateSpVersionTableTest.php
 create mode 100644 tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000400CreateUserTableTest.php
 create mode 100644 tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000500CreateUserVersionTableTest.php
 create mode 100644 tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000600CreateIdpSpUserVersionTableTest.php
 create mode 100644 tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000700CreateAuthenticationEventTableTest.php
 create mode 100644 tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawActivityTest.php
 create mode 100644 tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawConnectedServiceProviderTest.php
 create mode 100644 tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RepositoryTest.php
 create mode 100644 tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/StoreTest.php
 create mode 100644 tests/src/Stores/Jobs/DoctrineDbal/Store/Migrations/Version20220601000000CreateJobTableTest.php
 create mode 100644 tests/src/Stores/Jobs/DoctrineDbal/Store/Migrations/Version20220601000100CreateJobFailedTableTest.php
 create mode 100644 tests/src/Stores/Jobs/DoctrineDbal/Store/RawJobTest.php
 create mode 100644 tests/src/Stores/Jobs/DoctrineDbal/Store/RepositoryTest.php
 create mode 100644 tests/src/Stores/Jobs/DoctrineDbal/StoreTest.php
 create mode 100644 tests/src/Stores/Jobs/PhpRedis/RedisStoreTest.php
 create mode 100644 tests/src/Trackers/Authentication/DoctrineDbal/Versioned/TrackerTest.php
 create mode 100644 tests/src/Trackers/Builders/AuthenticationDataTrackerBuilderTest.php
 create mode 100644 www/assets/css/src/custom.css
 create mode 100644 www/assets/css/src/default.css
 create mode 100644 www/assets/css/src/fonts/raleway-v28-latin-ext_latin-300.woff
 create mode 100644 www/assets/css/src/fonts/raleway-v28-latin-ext_latin-300.woff2
 create mode 100644 www/assets/css/src/fonts/raleway-v28-latin-ext_latin-500.woff
 create mode 100644 www/assets/css/src/fonts/raleway-v28-latin-ext_latin-500.woff2
 create mode 100644 www/assets/css/src/fonts/raleway-v28-latin-ext_latin-600.woff
 create mode 100644 www/assets/css/src/fonts/raleway-v28-latin-ext_latin-600.woff2
 create mode 100644 www/assets/css/src/fonts/raleway-v28-latin-ext_latin-regular.woff
 create mode 100644 www/assets/css/src/fonts/raleway-v28-latin-ext_latin-regular.woff2
 create mode 100644 www/assets/css/src/icons/activity.svg
 create mode 100644 www/assets/css/src/icons/conn-orgs.svg
 create mode 100644 www/assets/css/src/icons/download.svg
 create mode 100644 www/assets/css/src/icons/dropdown.svg
 create mode 100644 www/assets/css/src/icons/fppp-logo.svg
 create mode 100644 www/assets/css/src/icons/i.svg
 create mode 100644 www/assets/css/src/icons/logout.svg
 create mode 100644 www/assets/css/src/icons/prof-page.svg
 create mode 100644 www/assets/css/src/icons/x.svg

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6aac9a0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+/.idea/
+/vendor/
+/build/
+.phpunit.result.cache
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..8000a6f
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,504 @@
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+                  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                            NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+    USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random
+  Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/README.md b/README.md
index 545213a..c623a6f 100644
--- a/README.md
+++ b/README.md
@@ -1,92 +1,124 @@
-# simpleSAMLphp
+# simplesamlphp-module-accounting
+SimpleSAMLphp module providing user accounting functionality using SimpleSAMLphp authentication processing 
+filters feature.
+
+## Features
+- Enables tracking of authentication events, synchronously (during authentication event) or
+asynchronously (in a separate process using SimpleSAMLphp Cron feature)
+- Provides endpoints for end users to check their personal data, summary on connected
+Service Providers, and list of authentication events
+- Comes with default [DBAL backend storage](https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/index.html),
+meaning the following database vendors can be used: MySQL, Oracle, Microsoft SQL Server, PostgreSQL, SQLite. Other
+backend storages can be added by following proper interfaces.
+- Comes with setup procedure which sets up backend storage. In case of Doctrine DBAL this means running SQL migrations
+which create proper tables in configured database.
+- Each backend storage connection can have master and slave configuration (master for writing, slave for reading)
+- Has "trackers" which persist authentication data to backend storage. Currently, there is one default Doctrine DBAL
+compatible tracker which stores authentication events, versioned Idp and SP metadata, and versioned user attributes.
+Other trackers can be added by following proper interfaces.
+- Trackers can run in two ways:
+  - synchronously - authentication data persisted during authentication event typically with multiple
+  queries / inserts / updates to backend storage.
+  - asynchronously - only authentication event job is persisted during authentication event
+  (one insert to backend storage). With this approach, authentication event jobs can be executed later in a separate
+  process using SimpleSAMLphp cron module
 
+## Installation
+Module requires SimpleSAMLphp version 2 or higher.
 
+Module is installable using Composer:
 
-## Getting started
-
-To make it easy for you to get started with GitLab, here's a list of recommended next steps.
-
-Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
-
-## Add your files
-
-- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
-- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
-
+```shell
+composer require cicnavi/simplesamlphp-module-accounting
 ```
-cd existing_repo
-git remote add origin https://gitlab.geant.org/TI_Incubator/personal-profile-page/simplesamlphp.git
-git branch -M main
-git push -uf origin main
-```
-
-## Integrate with your tools
 
-- [ ] [Set up project integrations](https://gitlab.geant.org/TI_Incubator/personal-profile-page/simplesamlphp/-/settings/integrations)
+Depending on used features, module also requires:
+- ext-redis: if PhpRedis is to be used as a store
 
-## Collaborate with your team
+## Configuration
+As usual with SimpleSAMLphp modules, copy the module template configuration
+to the SimpleSAMLphp config directory:
 
-- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
-- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
-- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
-- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
-- [ ] [Automatically merge when pipeline succeeds](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
-
-## Test and Deploy
-
-Use the built-in continuous integration in GitLab.
+```shell
+cp modules/accounting/config-templates/module_accounting.php config/
+```
 
-- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
-- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
-- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
-- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
-- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
+Next step is configuring available options in file config/module_accounting.php. Each option has an explanation,
+however, the description of the overall concept follows.
 
-***
+For accounting processing, the default data tracker and data provider class must be set. This tracker will be used
+to persist tracking data and also to show data in the SimpleSAMLphp user interface. Here is an example excerpt
+of setting the Doctrine DBAL compatible tracker class which will store authentication events, versioned Idp
+and SP metadata, and versioned user attributes in a relational database:
 
-# Editing this README
+```php
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Trackers;
 
-When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!).  Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template.
+// ...
+ModuleConfiguration::OPTION_DEFAULT_DATA_TRACKER_AND_PROVIDER =>
+    Trackers\Authentication\DoctrineDbal\Versioned\Tracker::class,
+// ...
+```
 
-## Suggestions for a good README
-Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
+The deployer can choose if the accounting processing will be performed during authentication event (synchronously),
+or in a separate process (asynchronously), for example:
 
-## Name
-Choose a self-explaining name for your project.
+```php
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\ModuleConfiguration\AccountingProcessingType;
 
-## Description
-Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
+// ...
+ModuleConfiguration::OPTION_ACCOUNTING_PROCESSING_TYPE =>
+    ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS,
+// ...
+```
 
-## Badges
-On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
+If the processing type is asynchronous, then the deployer must also configure the job store related options:
+- Jobs store class which will be used to store and fetch jobs from the backend store
+- Accounting cron tag for job runner
+- Cron module configuration (if the used tag is different from the ones available in cron module, which is the case
+by default)
 
-## Visuals
-Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
+For each tracker or job store, the "connection key" must be set. Connection key determines which connection
+parameters will be forwarded for tracker / job store initialization process.
 
-## Installation
-Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
+Also review / edit all other configuration options, and set appropriate values. 
 
-## Usage
-Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
+### Running Setup
 
-## Support
-Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
+After you have configured everything in config/module_accounting.php, go to the SimpleSAMLphp Admin > Configuration
+Page. There you will find a link "Accounting configuration status", which will take you on the 
+module configuration overview page.
 
-## Roadmap
-If you have ideas for releases in the future, it is a good idea to list them in the README.
+If the configured trackers / jobs store require any setup, you will see a "Run Setup" button, so go ahead
+and click it. In the case of default Doctrine DBAL tracker / jobs store, the setup will run all migration
+classes used to create necessary tables in the database.
 
-## Contributing
-State if you are open to contributions and what your requirements are for accepting them.
+When the setup is finished, you'll be presented with the "Profile Page" link, which can be used by end
+users to see their activity.
 
-For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
+### Adding Authentication Processing Filter
+Last step to start tracking user data using the configured tracker classes / jobs store is to add an [authentication
+processing filter](https://simplesamlphp.org/docs/stable/simplesamlphp-authproc.html) from the accounting module
+to the right place in SimpleSAMLphp configuration. Here is an example of setting it globally for all IdPs 
+in config/config.php:
 
-You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
+```php
+// ...
+'authproc.idp' => [
+        // ... 
+        1000 => 'accounting:Accounting',
+    ],
+// ...
+```
 
-## Authors and acknowledgment
-Show your appreciation to those who have contributed to the project.
+## TODO
+- [ ] Translation
 
-## License
-For open source projects, say how it is licensed.
+## Tests
+To run phpcs, psalm and phpunit:
 
-## Project status
-If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
+```shell
+composer pre-commit
+```
\ No newline at end of file
diff --git a/bin/test.php b/bin/test.php
new file mode 100644
index 0000000..cf32aff
--- /dev/null
+++ b/bin/test.php
@@ -0,0 +1,140 @@
+#!/usr/bin/env php
+<?php
+// TODO mivanci remove this file before release
+declare(strict_types=1);
+
+use SimpleSAML\Module\accounting\Entities\Authentication\Event;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event\Job;
+use SimpleSAML\Module\accounting\Entities\Authentication\State;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+use SimpleSAML\Module\accounting\Services\Logger;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection;
+use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Repository;
+use SimpleSAML\Module\accounting\Stores\Jobs\PhpRedis\RedisStore;
+
+require 'vendor/autoload.php';
+
+$helpersManager = new HelpersManager();
+
+$start = new DateTime();
+
+$newLine = "\n";
+
+echo "Start: " . $start->format(DateTime::ATOM);
+echo $newLine;
+
+$job = new Job(new Event(new State(SimpleSAML\Test\Module\accounting\Constants\StateArrays::FULL)));
+
+$options = getopt('c:');
+
+$numberOfItems = $options['c'] ?? 1000;
+
+echo 'Number of items: ' . $numberOfItems;
+echo $newLine;
+
+$spinnerChars = ['|', '/', '-', '\\'];
+
+/**/
+echo 'Starting simulating MySQL: ';
+$mysqlStartTime = new DateTime();
+echo $mysqlStartTime->format(DateTime::ATOM);
+echo $newLine;
+
+$mysqlParameters = [
+    'driver' => 'pdo_mysql', // (string): The built-in driver implementation to use
+    'user' => 'apps', // (string): Username to use when connecting to the database.
+    'password' => 'apps', // (string): Password to use when connecting to the database.
+    'host' => '127.0.0.1', // (string): Hostname of the database to connect to.
+    'port' => 33306, // (integer): Port of the database to connect to.
+    'dbname' => 'accounting', // (string): Name of the database/schema to connect to.
+    //'unix_socket' => 'unix_socet', // (string): Name of the socket used to connect to the database.
+    'charset' => 'utf8', // (string): The charset used when connecting to the database.
+    //'url' => 'mysql://user:secret@localhost/mydb?charset=utf8', // ...alternative way of providing parameters.
+    // Additional parameters not originally avaliable in Doctrine DBAL
+    'table_prefix' => '', // (string): Prefix for each table.
+];
+
+$logger = new Logger();
+
+$jobsStoreRepository = new Repository(new Connection($mysqlParameters), 'job', $logger);
+$mysqlDurationInSeconds = (new DateTime())->getTimestamp() - $mysqlStartTime->getTimestamp();
+$mysqlItemsInCurrentSecond = 0;
+$mysqlItemsPerSecond = [];
+for ($i = 1; $i <= $numberOfItems; $i++) {
+    $mysqlUpdatedDurationInSeconds = (new DateTime())->getTimestamp() - $mysqlStartTime->getTimestamp();
+    if ($mysqlDurationInSeconds === $mysqlUpdatedDurationInSeconds) {
+        $mysqlItemsInCurrentSecond++;
+    } else {
+        $mysqlItemsPerSecond[] = $mysqlItemsInCurrentSecond;
+        $mysqlItemsInCurrentSecond = 0;
+    }
+    $mysqlItemsInCurrentSecond = $mysqlDurationInSeconds === $mysqlUpdatedDurationInSeconds ?
+        $mysqlItemsInCurrentSecond++ : 0;
+    $mysqlDurationInSeconds = (new DateTime())->getTimestamp() - $mysqlStartTime->getTimestamp();
+
+    $mysqlItemsPerSeconds = count($mysqlItemsPerSecond) ?
+        array_sum($mysqlItemsPerSecond) / count($mysqlItemsPerSecond) : 0;
+    $mysqlPercentage = $i / $numberOfItems  * 100;
+    $spinnerChar = $spinnerChars[array_rand($spinnerChars)];
+    $line = sprintf(
+        '%1$s percentage: %2$ 3d%%, items/s: %3$04d, duration: %4$ss',
+        $spinnerChar, $mysqlPercentage, $mysqlItemsPerSeconds, $mysqlDurationInSeconds
+    );
+    echo $line;
+    echo "\r";
+    $jobsStoreRepository->insert($job);
+}
+echo $newLine;
+echo $newLine;
+
+
+echo 'Starting simulating Redis: ';
+$redisStartTime = new DateTime();
+echo $redisStartTime->format(DateTime::ATOM);
+echo $newLine;
+
+$redisClient = new Redis();
+$redisClient->connect(
+    '127.0.0.1',
+    6379,
+    1,
+    null,
+    500,
+    1
+);
+$redisClient->auth('apps');
+$redisClient->setOption(Redis::OPT_PREFIX, 'ssp_accounting:');
+
+
+$redisDurationInSeconds = (new DateTime())->getTimestamp() - $redisStartTime->getTimestamp();
+$redisItemsInCurrentSecond = 0;
+$redisItemsPerSecond = [];
+for ($i = 1; $i <= $numberOfItems; $i++) {
+    $redisUpdatedDurationInSeconds = (new DateTime())->getTimestamp() - $redisStartTime->getTimestamp();
+    if ($redisDurationInSeconds === $redisUpdatedDurationInSeconds) {
+        $redisItemsInCurrentSecond++;
+    } else {
+        $redisItemsPerSecond[] = $redisItemsInCurrentSecond;
+        $redisItemsInCurrentSecond = 0;
+    }
+    $redisItemsInCurrentSecond = $redisDurationInSeconds === $redisUpdatedDurationInSeconds ?
+        $redisItemsInCurrentSecond++ : 0;
+
+    $redisDurationInSeconds = $redisUpdatedDurationInSeconds;
+
+    $redisItemsPerSeconds = count($redisItemsPerSecond) ?
+        array_sum($redisItemsPerSecond) / count($redisItemsPerSecond) : 0;
+    $redisPercentage = $i / $numberOfItems  * 100;
+    $spinnerChar = $spinnerChars[array_rand($spinnerChars)];
+    $line = sprintf(
+        '%1$s percentage: %2$ 3d%%, items/s: %3$04d, duration: %4$ss',
+        $spinnerChar, $redisPercentage, $redisItemsPerSeconds, $redisDurationInSeconds
+    );
+    echo $line;
+    echo "\r";
+    $redisClient->rPush(RedisStore::LIST_KEY_JOB . ':' . sha1($job->getType()), serialize($job));
+//    $redisClient->rPush(RedisStore::LIST_KEY_JOB, serializgit add .e($job));
+}
+echo $newLine;
+echo 'End: ' . (new DateTime())->format(DateTime::ATOM);
+echo $newLine;
\ No newline at end of file
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..c7e7ffa
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,54 @@
+{
+    "name": "cicnavi/simplesamlphp-module-accounting",
+    "description": "The SimpleSAMLphp accounting module",
+    "type": "simplesamlphp-module",
+    "license": "LGPL-2.1-or-later",
+    "authors": [
+        {
+            "name": "Marko Ivančić",
+            "email": "marko.ivancic@srce.hr"
+        }
+    ],
+    "config": {
+        "allow-plugins": {
+            "simplesamlphp/composer-module-installer": true
+        }
+    },
+    "autoload": {
+        "psr-4": {
+            "SimpleSAML\\Module\\accounting\\": "src/"
+        }
+    },
+    "autoload-dev": {
+        "psr-4": {
+            "SimpleSAML\\Test\\Module\\accounting\\": "tests/src/"
+        }
+    },
+    "require": {
+        "php": "^7.4 || ^8.0",
+        "ext-pdo": "*",
+        "ext-pdo_sqlite": "*",
+        "doctrine/dbal": "^3",
+        "psr/log": "^1|^2|^3",
+        "simplesamlphp/composer-module-installer": "^1",
+        "cicnavi/simple-file-cache-php": "^2.0"
+    },
+    "require-dev": {
+        "vimeo/psalm": "^4",
+        "phpunit/phpunit": "^9",
+        "squizlabs/php_codesniffer": "^3",
+        "simplesamlphp/simplesamlphp": "^2@beta",
+        "simplesamlphp/simplesamlphp-test-framework": "^1"
+    },
+    "suggest": {
+        "ext-pcntl": "Enables job runner to gracefully respond to SIGTERM signal.",
+        "ext-redis": "Mandatory if PhpRedis is to be used as a store."
+    },
+    "scripts": {
+        "pre-commit": [
+            "vendor/bin/phpcs -p",
+            "vendor/bin/psalm",
+            "vendor/bin/phpunit"
+        ]
+    }
+}
diff --git a/composer.lock b/composer.lock
new file mode 100644
index 0000000..40bbe7f
--- /dev/null
+++ b/composer.lock
@@ -0,0 +1,7776 @@
+{
+    "_readme": [
+        "This file locks the dependencies of your project to a known state",
+        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
+        "This file is @generated automatically"
+    ],
+    "content-hash": "e1bdcb1340cc34e659c651695992a6b8",
+    "packages": [
+        {
+            "name": "cicnavi/simple-file-cache-php",
+            "version": "v2.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/cicnavi/simple-file-cache-php.git",
+                "reference": "372b48b5ff364e514da80005b2367ecf1950dde4"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/cicnavi/simple-file-cache-php/zipball/372b48b5ff364e514da80005b2367ecf1950dde4",
+                "reference": "372b48b5ff364e514da80005b2367ecf1950dde4",
+                "shasum": ""
+            },
+            "require": {
+                "ext-gmp": "*",
+                "ext-json": "*",
+                "ext-openssl": "*",
+                "php": ">=7.4",
+                "psr/simple-cache": "^1.0"
+            },
+            "provide": {
+                "psr/simple-cache-implementation": "1.0"
+            },
+            "require-dev": {
+                "ext-xdebug": "*",
+                "phpunit/phpunit": "^9.4",
+                "squizlabs/php_codesniffer": "^3.5",
+                "vimeo/psalm": "^3.14"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Cicnavi\\SimpleFileCache\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Marko Ivancic",
+                    "email": "marko.ivancic@srce.hr"
+                }
+            ],
+            "description": "PSR-16 simple cache provider based on files.",
+            "support": {
+                "issues": "https://github.com/cicnavi/simple-file-cache-php/issues",
+                "source": "https://github.com/cicnavi/simple-file-cache-php/tree/v2.0.0"
+            },
+            "time": "2021-08-18T11:28:21+00:00"
+        },
+        {
+            "name": "composer/ca-bundle",
+            "version": "1.3.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/composer/ca-bundle.git",
+                "reference": "30897edbfb15e784fe55587b4f73ceefd3c4d98c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/composer/ca-bundle/zipball/30897edbfb15e784fe55587b4f73ceefd3c4d98c",
+                "reference": "30897edbfb15e784fe55587b4f73ceefd3c4d98c",
+                "shasum": ""
+            },
+            "require": {
+                "ext-openssl": "*",
+                "ext-pcre": "*",
+                "php": "^5.3.2 || ^7.0 || ^8.0"
+            },
+            "require-dev": {
+                "phpstan/phpstan": "^0.12.55",
+                "psr/log": "^1.0",
+                "symfony/phpunit-bridge": "^4.2 || ^5",
+                "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0 || ^6.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Composer\\CaBundle\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jordi Boggiano",
+                    "email": "j.boggiano@seld.be",
+                    "homepage": "http://seld.be"
+                }
+            ],
+            "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.",
+            "keywords": [
+                "cabundle",
+                "cacert",
+                "certificate",
+                "ssl",
+                "tls"
+            ],
+            "support": {
+                "irc": "irc://irc.freenode.org/composer",
+                "issues": "https://github.com/composer/ca-bundle/issues",
+                "source": "https://github.com/composer/ca-bundle/tree/1.3.3"
+            },
+            "funding": [
+                {
+                    "url": "https://packagist.com",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/composer",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-07-20T07:14:26+00:00"
+        },
+        {
+            "name": "composer/class-map-generator",
+            "version": "1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/composer/class-map-generator.git",
+                "reference": "1e1cb2b791facb2dfe32932a7718cf2571187513"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/composer/class-map-generator/zipball/1e1cb2b791facb2dfe32932a7718cf2571187513",
+                "reference": "1e1cb2b791facb2dfe32932a7718cf2571187513",
+                "shasum": ""
+            },
+            "require": {
+                "composer/pcre": "^2 || ^3",
+                "php": "^7.2 || ^8.0",
+                "symfony/finder": "^4.4 || ^5.3 || ^6"
+            },
+            "require-dev": {
+                "phpstan/phpstan": "^1.6",
+                "phpstan/phpstan-deprecation-rules": "^1",
+                "phpstan/phpstan-phpunit": "^1",
+                "phpstan/phpstan-strict-rules": "^1.1",
+                "symfony/filesystem": "^5.4 || ^6",
+                "symfony/phpunit-bridge": "^5"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Composer\\ClassMapGenerator\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jordi Boggiano",
+                    "email": "j.boggiano@seld.be",
+                    "homepage": "https://seld.be"
+                }
+            ],
+            "description": "Utilities to scan PHP code and generate class maps.",
+            "keywords": [
+                "classmap"
+            ],
+            "support": {
+                "issues": "https://github.com/composer/class-map-generator/issues",
+                "source": "https://github.com/composer/class-map-generator/tree/1.0.0"
+            },
+            "funding": [
+                {
+                    "url": "https://packagist.com",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/composer",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-06-19T11:31:27+00:00"
+        },
+        {
+            "name": "composer/composer",
+            "version": "2.4.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/composer/composer.git",
+                "reference": "7d887621e69a0311eb50aed4a16f7044b2b385b9"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/composer/composer/zipball/7d887621e69a0311eb50aed4a16f7044b2b385b9",
+                "reference": "7d887621e69a0311eb50aed4a16f7044b2b385b9",
+                "shasum": ""
+            },
+            "require": {
+                "composer/ca-bundle": "^1.0",
+                "composer/class-map-generator": "^1.0",
+                "composer/metadata-minifier": "^1.0",
+                "composer/pcre": "^2 || ^3",
+                "composer/semver": "^3.0",
+                "composer/spdx-licenses": "^1.5.7",
+                "composer/xdebug-handler": "^2.0.2 || ^3.0.3",
+                "justinrainbow/json-schema": "^5.2.11",
+                "php": "^7.2.5 || ^8.0",
+                "psr/log": "^1.0 || ^2.0 || ^3.0",
+                "react/promise": "^2.8",
+                "seld/jsonlint": "^1.4",
+                "seld/phar-utils": "^1.2",
+                "seld/signal-handler": "^2.0",
+                "symfony/console": "^5.4.11 || ^6.0.11",
+                "symfony/filesystem": "^5.4 || ^6.0",
+                "symfony/finder": "^5.4 || ^6.0",
+                "symfony/polyfill-php73": "^1.24",
+                "symfony/polyfill-php80": "^1.24",
+                "symfony/process": "^5.4 || ^6.0"
+            },
+            "require-dev": {
+                "phpstan/phpstan": "^1.4.1",
+                "phpstan/phpstan-deprecation-rules": "^1",
+                "phpstan/phpstan-phpunit": "^1.0",
+                "phpstan/phpstan-strict-rules": "^1",
+                "phpstan/phpstan-symfony": "^1.2.10",
+                "symfony/phpunit-bridge": "^6.0"
+            },
+            "suggest": {
+                "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages",
+                "ext-zip": "Enabling the zip extension allows you to unzip archives",
+                "ext-zlib": "Allow gzip compression of HTTP requests"
+            },
+            "bin": [
+                "bin/composer"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "2.4-dev"
+                },
+                "phpstan": {
+                    "includes": [
+                        "phpstan/rules.neon"
+                    ]
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Composer\\": "src/Composer"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nils Adermann",
+                    "email": "naderman@naderman.de",
+                    "homepage": "https://www.naderman.de"
+                },
+                {
+                    "name": "Jordi Boggiano",
+                    "email": "j.boggiano@seld.be",
+                    "homepage": "https://seld.be"
+                }
+            ],
+            "description": "Composer helps you declare, manage and install dependencies of PHP projects. It ensures you have the right stack everywhere.",
+            "homepage": "https://getcomposer.org/",
+            "keywords": [
+                "autoload",
+                "dependency",
+                "package"
+            ],
+            "support": {
+                "irc": "ircs://irc.libera.chat:6697/composer",
+                "issues": "https://github.com/composer/composer/issues",
+                "source": "https://github.com/composer/composer/tree/2.4.2"
+            },
+            "funding": [
+                {
+                    "url": "https://packagist.com",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/composer",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-09-14T14:11:15+00:00"
+        },
+        {
+            "name": "composer/metadata-minifier",
+            "version": "1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/composer/metadata-minifier.git",
+                "reference": "c549d23829536f0d0e984aaabbf02af91f443207"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/composer/metadata-minifier/zipball/c549d23829536f0d0e984aaabbf02af91f443207",
+                "reference": "c549d23829536f0d0e984aaabbf02af91f443207",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.3.2 || ^7.0 || ^8.0"
+            },
+            "require-dev": {
+                "composer/composer": "^2",
+                "phpstan/phpstan": "^0.12.55",
+                "symfony/phpunit-bridge": "^4.2 || ^5"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Composer\\MetadataMinifier\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jordi Boggiano",
+                    "email": "j.boggiano@seld.be",
+                    "homepage": "http://seld.be"
+                }
+            ],
+            "description": "Small utility library that handles metadata minification and expansion.",
+            "keywords": [
+                "composer",
+                "compression"
+            ],
+            "support": {
+                "issues": "https://github.com/composer/metadata-minifier/issues",
+                "source": "https://github.com/composer/metadata-minifier/tree/1.0.0"
+            },
+            "funding": [
+                {
+                    "url": "https://packagist.com",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/composer",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2021-04-07T13:37:33+00:00"
+        },
+        {
+            "name": "composer/pcre",
+            "version": "3.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/composer/pcre.git",
+                "reference": "e300eb6c535192decd27a85bc72a9290f0d6b3bd"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/composer/pcre/zipball/e300eb6c535192decd27a85bc72a9290f0d6b3bd",
+                "reference": "e300eb6c535192decd27a85bc72a9290f0d6b3bd",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.4 || ^8.0"
+            },
+            "require-dev": {
+                "phpstan/phpstan": "^1.3",
+                "phpstan/phpstan-strict-rules": "^1.1",
+                "symfony/phpunit-bridge": "^5"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "3.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Composer\\Pcre\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jordi Boggiano",
+                    "email": "j.boggiano@seld.be",
+                    "homepage": "http://seld.be"
+                }
+            ],
+            "description": "PCRE wrapping library that offers type-safe preg_* replacements.",
+            "keywords": [
+                "PCRE",
+                "preg",
+                "regex",
+                "regular expression"
+            ],
+            "support": {
+                "issues": "https://github.com/composer/pcre/issues",
+                "source": "https://github.com/composer/pcre/tree/3.0.0"
+            },
+            "funding": [
+                {
+                    "url": "https://packagist.com",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/composer",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-02-25T20:21:48+00:00"
+        },
+        {
+            "name": "composer/semver",
+            "version": "3.3.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/composer/semver.git",
+                "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9",
+                "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.3.2 || ^7.0 || ^8.0"
+            },
+            "require-dev": {
+                "phpstan/phpstan": "^1.4",
+                "symfony/phpunit-bridge": "^4.2 || ^5"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "3.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Composer\\Semver\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nils Adermann",
+                    "email": "naderman@naderman.de",
+                    "homepage": "http://www.naderman.de"
+                },
+                {
+                    "name": "Jordi Boggiano",
+                    "email": "j.boggiano@seld.be",
+                    "homepage": "http://seld.be"
+                },
+                {
+                    "name": "Rob Bast",
+                    "email": "rob.bast@gmail.com",
+                    "homepage": "http://robbast.nl"
+                }
+            ],
+            "description": "Semver library that offers utilities, version constraint parsing and validation.",
+            "keywords": [
+                "semantic",
+                "semver",
+                "validation",
+                "versioning"
+            ],
+            "support": {
+                "irc": "irc://irc.freenode.org/composer",
+                "issues": "https://github.com/composer/semver/issues",
+                "source": "https://github.com/composer/semver/tree/3.3.2"
+            },
+            "funding": [
+                {
+                    "url": "https://packagist.com",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/composer",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-04-01T19:23:25+00:00"
+        },
+        {
+            "name": "composer/spdx-licenses",
+            "version": "1.5.7",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/composer/spdx-licenses.git",
+                "reference": "c848241796da2abf65837d51dce1fae55a960149"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/c848241796da2abf65837d51dce1fae55a960149",
+                "reference": "c848241796da2abf65837d51dce1fae55a960149",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.3.2 || ^7.0 || ^8.0"
+            },
+            "require-dev": {
+                "phpstan/phpstan": "^0.12.55",
+                "symfony/phpunit-bridge": "^4.2 || ^5"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Composer\\Spdx\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nils Adermann",
+                    "email": "naderman@naderman.de",
+                    "homepage": "http://www.naderman.de"
+                },
+                {
+                    "name": "Jordi Boggiano",
+                    "email": "j.boggiano@seld.be",
+                    "homepage": "http://seld.be"
+                },
+                {
+                    "name": "Rob Bast",
+                    "email": "rob.bast@gmail.com",
+                    "homepage": "http://robbast.nl"
+                }
+            ],
+            "description": "SPDX licenses list and validation library.",
+            "keywords": [
+                "license",
+                "spdx",
+                "validator"
+            ],
+            "support": {
+                "irc": "irc://irc.freenode.org/composer",
+                "issues": "https://github.com/composer/spdx-licenses/issues",
+                "source": "https://github.com/composer/spdx-licenses/tree/1.5.7"
+            },
+            "funding": [
+                {
+                    "url": "https://packagist.com",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/composer",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-05-23T07:37:50+00:00"
+        },
+        {
+            "name": "composer/xdebug-handler",
+            "version": "3.0.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/composer/xdebug-handler.git",
+                "reference": "ced299686f41dce890debac69273b47ffe98a40c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ced299686f41dce890debac69273b47ffe98a40c",
+                "reference": "ced299686f41dce890debac69273b47ffe98a40c",
+                "shasum": ""
+            },
+            "require": {
+                "composer/pcre": "^1 || ^2 || ^3",
+                "php": "^7.2.5 || ^8.0",
+                "psr/log": "^1 || ^2 || ^3"
+            },
+            "require-dev": {
+                "phpstan/phpstan": "^1.0",
+                "phpstan/phpstan-strict-rules": "^1.1",
+                "symfony/phpunit-bridge": "^6.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Composer\\XdebugHandler\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "John Stevenson",
+                    "email": "john-stevenson@blueyonder.co.uk"
+                }
+            ],
+            "description": "Restarts a process without Xdebug.",
+            "keywords": [
+                "Xdebug",
+                "performance"
+            ],
+            "support": {
+                "irc": "irc://irc.freenode.org/composer",
+                "issues": "https://github.com/composer/xdebug-handler/issues",
+                "source": "https://github.com/composer/xdebug-handler/tree/3.0.3"
+            },
+            "funding": [
+                {
+                    "url": "https://packagist.com",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/composer",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-02-25T21:32:43+00:00"
+        },
+        {
+            "name": "doctrine/cache",
+            "version": "2.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/cache.git",
+                "reference": "1ca8f21980e770095a31456042471a57bc4c68fb"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/cache/zipball/1ca8f21980e770095a31456042471a57bc4c68fb",
+                "reference": "1ca8f21980e770095a31456042471a57bc4c68fb",
+                "shasum": ""
+            },
+            "require": {
+                "php": "~7.1 || ^8.0"
+            },
+            "conflict": {
+                "doctrine/common": ">2.2,<2.4"
+            },
+            "require-dev": {
+                "cache/integration-tests": "dev-master",
+                "doctrine/coding-standard": "^9",
+                "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
+                "psr/cache": "^1.0 || ^2.0 || ^3.0",
+                "symfony/cache": "^4.4 || ^5.4 || ^6",
+                "symfony/var-exporter": "^4.4 || ^5.4 || ^6"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com"
+                },
+                {
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                },
+                {
+                    "name": "Jonathan Wage",
+                    "email": "jonwage@gmail.com"
+                },
+                {
+                    "name": "Johannes Schmitt",
+                    "email": "schmittjoh@gmail.com"
+                }
+            ],
+            "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.",
+            "homepage": "https://www.doctrine-project.org/projects/cache.html",
+            "keywords": [
+                "abstraction",
+                "apcu",
+                "cache",
+                "caching",
+                "couchdb",
+                "memcached",
+                "php",
+                "redis",
+                "xcache"
+            ],
+            "support": {
+                "issues": "https://github.com/doctrine/cache/issues",
+                "source": "https://github.com/doctrine/cache/tree/2.2.0"
+            },
+            "funding": [
+                {
+                    "url": "https://www.doctrine-project.org/sponsorship.html",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://www.patreon.com/phpdoctrine",
+                    "type": "patreon"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcache",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-05-20T20:07:39+00:00"
+        },
+        {
+            "name": "doctrine/dbal",
+            "version": "3.4.5",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/dbal.git",
+                "reference": "a5a58773109c0abb13e658c8ccd92aeec8d07f9e"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/dbal/zipball/a5a58773109c0abb13e658c8ccd92aeec8d07f9e",
+                "reference": "a5a58773109c0abb13e658c8ccd92aeec8d07f9e",
+                "shasum": ""
+            },
+            "require": {
+                "composer-runtime-api": "^2",
+                "doctrine/cache": "^1.11|^2.0",
+                "doctrine/deprecations": "^0.5.3|^1",
+                "doctrine/event-manager": "^1.0",
+                "php": "^7.4 || ^8.0",
+                "psr/cache": "^1|^2|^3",
+                "psr/log": "^1|^2|^3"
+            },
+            "require-dev": {
+                "doctrine/coding-standard": "10.0.0",
+                "jetbrains/phpstorm-stubs": "2022.2",
+                "phpstan/phpstan": "1.8.3",
+                "phpstan/phpstan-strict-rules": "^1.3",
+                "phpunit/phpunit": "9.5.24",
+                "psalm/plugin-phpunit": "0.17.0",
+                "squizlabs/php_codesniffer": "3.7.1",
+                "symfony/cache": "^5.4|^6.0",
+                "symfony/console": "^4.4|^5.4|^6.0",
+                "vimeo/psalm": "4.27.0"
+            },
+            "suggest": {
+                "symfony/console": "For helpful console commands such as SQL execution and import of files."
+            },
+            "bin": [
+                "bin/doctrine-dbal"
+            ],
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Doctrine\\DBAL\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com"
+                },
+                {
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                },
+                {
+                    "name": "Jonathan Wage",
+                    "email": "jonwage@gmail.com"
+                }
+            ],
+            "description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.",
+            "homepage": "https://www.doctrine-project.org/projects/dbal.html",
+            "keywords": [
+                "abstraction",
+                "database",
+                "db2",
+                "dbal",
+                "mariadb",
+                "mssql",
+                "mysql",
+                "oci8",
+                "oracle",
+                "pdo",
+                "pgsql",
+                "postgresql",
+                "queryobject",
+                "sasql",
+                "sql",
+                "sqlite",
+                "sqlserver",
+                "sqlsrv"
+            ],
+            "support": {
+                "issues": "https://github.com/doctrine/dbal/issues",
+                "source": "https://github.com/doctrine/dbal/tree/3.4.5"
+            },
+            "funding": [
+                {
+                    "url": "https://www.doctrine-project.org/sponsorship.html",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://www.patreon.com/phpdoctrine",
+                    "type": "patreon"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdbal",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-09-23T17:48:57+00:00"
+        },
+        {
+            "name": "doctrine/deprecations",
+            "version": "v1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/deprecations.git",
+                "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
+                "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.1|^8.0"
+            },
+            "require-dev": {
+                "doctrine/coding-standard": "^9",
+                "phpunit/phpunit": "^7.5|^8.5|^9.5",
+                "psr/log": "^1|^2|^3"
+            },
+            "suggest": {
+                "psr/log": "Allows logging deprecations via PSR-3 logger implementation"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
+            "homepage": "https://www.doctrine-project.org/",
+            "support": {
+                "issues": "https://github.com/doctrine/deprecations/issues",
+                "source": "https://github.com/doctrine/deprecations/tree/v1.0.0"
+            },
+            "time": "2022-05-02T15:47:09+00:00"
+        },
+        {
+            "name": "doctrine/event-manager",
+            "version": "1.1.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/event-manager.git",
+                "reference": "eb2ecf80e3093e8f3c2769ac838e27d8ede8e683"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/event-manager/zipball/eb2ecf80e3093e8f3c2769ac838e27d8ede8e683",
+                "reference": "eb2ecf80e3093e8f3c2769ac838e27d8ede8e683",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.1 || ^8.0"
+            },
+            "conflict": {
+                "doctrine/common": "<2.9"
+            },
+            "require-dev": {
+                "doctrine/coding-standard": "^9",
+                "phpstan/phpstan": "~1.4.10 || ^1.5.4",
+                "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
+                "vimeo/psalm": "^4.22"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Doctrine\\Common\\": "lib/Doctrine/Common"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com"
+                },
+                {
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                },
+                {
+                    "name": "Jonathan Wage",
+                    "email": "jonwage@gmail.com"
+                },
+                {
+                    "name": "Johannes Schmitt",
+                    "email": "schmittjoh@gmail.com"
+                },
+                {
+                    "name": "Marco Pivetta",
+                    "email": "ocramius@gmail.com"
+                }
+            ],
+            "description": "The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.",
+            "homepage": "https://www.doctrine-project.org/projects/event-manager.html",
+            "keywords": [
+                "event",
+                "event dispatcher",
+                "event manager",
+                "event system",
+                "events"
+            ],
+            "support": {
+                "issues": "https://github.com/doctrine/event-manager/issues",
+                "source": "https://github.com/doctrine/event-manager/tree/1.1.2"
+            },
+            "funding": [
+                {
+                    "url": "https://www.doctrine-project.org/sponsorship.html",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://www.patreon.com/phpdoctrine",
+                    "type": "patreon"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fevent-manager",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-07-27T22:18:11+00:00"
+        },
+        {
+            "name": "gettext/gettext",
+            "version": "v5.7.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-gettext/Gettext.git",
+                "reference": "8657e580747bb3baacccdcebe69cac094661e404"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-gettext/Gettext/zipball/8657e580747bb3baacccdcebe69cac094661e404",
+                "reference": "8657e580747bb3baacccdcebe69cac094661e404",
+                "shasum": ""
+            },
+            "require": {
+                "gettext/languages": "^2.3",
+                "php": "^7.2|^8.0"
+            },
+            "require-dev": {
+                "brick/varexporter": "^0.3.5",
+                "friendsofphp/php-cs-fixer": "^3.2",
+                "oscarotero/php-cs-fixer-config": "^2.0",
+                "phpunit/phpunit": "^8.0|^9.0",
+                "squizlabs/php_codesniffer": "^3.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Gettext\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Oscar Otero",
+                    "email": "oom@oscarotero.com",
+                    "homepage": "http://oscarotero.com",
+                    "role": "Developer"
+                }
+            ],
+            "description": "PHP gettext manager",
+            "homepage": "https://github.com/php-gettext/Gettext",
+            "keywords": [
+                "JS",
+                "gettext",
+                "i18n",
+                "mo",
+                "po",
+                "translation"
+            ],
+            "support": {
+                "email": "oom@oscarotero.com",
+                "issues": "https://github.com/php-gettext/Gettext/issues",
+                "source": "https://github.com/php-gettext/Gettext/tree/v5.7.0"
+            },
+            "funding": [
+                {
+                    "url": "https://paypal.me/oscarotero",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/oscarotero",
+                    "type": "github"
+                },
+                {
+                    "url": "https://www.patreon.com/misteroom",
+                    "type": "patreon"
+                }
+            ],
+            "time": "2022-07-27T19:54:55+00:00"
+        },
+        {
+            "name": "gettext/languages",
+            "version": "2.9.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-gettext/Languages.git",
+                "reference": "ed56dd2c7f4024cc953ed180d25f02f2640e3ffa"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-gettext/Languages/zipball/ed56dd2c7f4024cc953ed180d25f02f2640e3ffa",
+                "reference": "ed56dd2c7f4024cc953ed180d25f02f2640e3ffa",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.8 || ^5.7 || ^6.5 || ^7.5 || ^8.4"
+            },
+            "bin": [
+                "bin/export-plural-rules"
+            ],
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Gettext\\Languages\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Michele Locati",
+                    "email": "mlocati@gmail.com",
+                    "role": "Developer"
+                }
+            ],
+            "description": "gettext languages with plural rules",
+            "homepage": "https://github.com/php-gettext/Languages",
+            "keywords": [
+                "cldr",
+                "i18n",
+                "internationalization",
+                "l10n",
+                "language",
+                "languages",
+                "localization",
+                "php",
+                "plural",
+                "plural rules",
+                "plurals",
+                "translate",
+                "translations",
+                "unicode"
+            ],
+            "support": {
+                "issues": "https://github.com/php-gettext/Languages/issues",
+                "source": "https://github.com/php-gettext/Languages/tree/2.9.0"
+            },
+            "funding": [
+                {
+                    "url": "https://paypal.me/mlocati",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/mlocati",
+                    "type": "github"
+                }
+            ],
+            "time": "2021-11-11T17:30:39+00:00"
+        },
+        {
+            "name": "gettext/translator",
+            "version": "v1.1.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-gettext/Translator.git",
+                "reference": "b18ff33e8203de623854561f5e47e992fc5c50bb"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-gettext/Translator/zipball/b18ff33e8203de623854561f5e47e992fc5c50bb",
+                "reference": "b18ff33e8203de623854561f5e47e992fc5c50bb",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.2|^8.0"
+            },
+            "require-dev": {
+                "friendsofphp/php-cs-fixer": "^2.15",
+                "gettext/gettext": "^5.0.0",
+                "oscarotero/php-cs-fixer-config": "^1.0",
+                "phpunit/phpunit": "^8.0",
+                "squizlabs/php_codesniffer": "^3.0"
+            },
+            "suggest": {
+                "gettext/gettext": "Is necessary to load and generate array files used by the translator"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Gettext\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Oscar Otero",
+                    "email": "oom@oscarotero.com",
+                    "homepage": "http://oscarotero.com",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Gettext translator functions",
+            "homepage": "https://github.com/php-gettext/Translator",
+            "keywords": [
+                "gettext",
+                "i18n",
+                "php",
+                "translator"
+            ],
+            "support": {
+                "email": "oom@oscarotero.com",
+                "issues": "https://github.com/php-gettext/Translator/issues",
+                "source": "https://github.com/php-gettext/Translator/tree/v1.1.1"
+            },
+            "funding": [
+                {
+                    "url": "https://paypal.me/oscarotero",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/oscarotero",
+                    "type": "github"
+                },
+                {
+                    "url": "https://www.patreon.com/misteroom",
+                    "type": "patreon"
+                }
+            ],
+            "time": "2022-02-23T20:29:40+00:00"
+        },
+        {
+            "name": "justinrainbow/json-schema",
+            "version": "5.2.12",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/justinrainbow/json-schema.git",
+                "reference": "ad87d5a5ca981228e0e205c2bc7dfb8e24559b60"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/ad87d5a5ca981228e0e205c2bc7dfb8e24559b60",
+                "reference": "ad87d5a5ca981228e0e205c2bc7dfb8e24559b60",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1",
+                "json-schema/json-schema-test-suite": "1.2.0",
+                "phpunit/phpunit": "^4.8.35"
+            },
+            "bin": [
+                "bin/validate-json"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "5.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "JsonSchema\\": "src/JsonSchema/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Bruno Prieto Reis",
+                    "email": "bruno.p.reis@gmail.com"
+                },
+                {
+                    "name": "Justin Rainbow",
+                    "email": "justin.rainbow@gmail.com"
+                },
+                {
+                    "name": "Igor Wiedler",
+                    "email": "igor@wiedler.ch"
+                },
+                {
+                    "name": "Robert Schönthal",
+                    "email": "seroscho@googlemail.com"
+                }
+            ],
+            "description": "A library to validate a json schema.",
+            "homepage": "https://github.com/justinrainbow/json-schema",
+            "keywords": [
+                "json",
+                "schema"
+            ],
+            "support": {
+                "issues": "https://github.com/justinrainbow/json-schema/issues",
+                "source": "https://github.com/justinrainbow/json-schema/tree/5.2.12"
+            },
+            "time": "2022-04-13T08:02:27+00:00"
+        },
+        {
+            "name": "phpmailer/phpmailer",
+            "version": "v6.6.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/PHPMailer/PHPMailer.git",
+                "reference": "a94fdebaea6bd17f51be0c2373ab80d3d681269b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/a94fdebaea6bd17f51be0c2373ab80d3d681269b",
+                "reference": "a94fdebaea6bd17f51be0c2373ab80d3d681269b",
+                "shasum": ""
+            },
+            "require": {
+                "ext-ctype": "*",
+                "ext-filter": "*",
+                "ext-hash": "*",
+                "php": ">=5.5.0"
+            },
+            "require-dev": {
+                "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
+                "doctrine/annotations": "^1.2",
+                "php-parallel-lint/php-console-highlighter": "^1.0.0",
+                "php-parallel-lint/php-parallel-lint": "^1.3.2",
+                "phpcompatibility/php-compatibility": "^9.3.5",
+                "roave/security-advisories": "dev-latest",
+                "squizlabs/php_codesniffer": "^3.6.2",
+                "yoast/phpunit-polyfills": "^1.0.0"
+            },
+            "suggest": {
+                "ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
+                "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
+                "league/oauth2-google": "Needed for Google XOAUTH2 authentication",
+                "psr/log": "For optional PSR-3 debug logging",
+                "stevenmaguire/oauth2-microsoft": "Needed for Microsoft XOAUTH2 authentication",
+                "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "PHPMailer\\PHPMailer\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "LGPL-2.1-only"
+            ],
+            "authors": [
+                {
+                    "name": "Marcus Bointon",
+                    "email": "phpmailer@synchromedia.co.uk"
+                },
+                {
+                    "name": "Jim Jagielski",
+                    "email": "jimjag@gmail.com"
+                },
+                {
+                    "name": "Andy Prevost",
+                    "email": "codeworxtech@users.sourceforge.net"
+                },
+                {
+                    "name": "Brent R. Matzelle"
+                }
+            ],
+            "description": "PHPMailer is a full-featured email creation and transfer class for PHP",
+            "support": {
+                "issues": "https://github.com/PHPMailer/PHPMailer/issues",
+                "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.6.4"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/Synchro",
+                    "type": "github"
+                }
+            ],
+            "time": "2022-08-22T09:22:00+00:00"
+        },
+        {
+            "name": "psr/cache",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/cache.git",
+                "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8",
+                "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Cache\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for caching libraries",
+            "keywords": [
+                "cache",
+                "psr",
+                "psr-6"
+            ],
+            "support": {
+                "source": "https://github.com/php-fig/cache/tree/master"
+            },
+            "time": "2016-08-06T20:24:11+00:00"
+        },
+        {
+            "name": "psr/container",
+            "version": "1.1.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/container.git",
+                "reference": "513e0666f7216c7459170d56df27dfcefe1689ea"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea",
+                "reference": "513e0666f7216c7459170d56df27dfcefe1689ea",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.4.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Container\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "https://www.php-fig.org/"
+                }
+            ],
+            "description": "Common Container Interface (PHP FIG PSR-11)",
+            "homepage": "https://github.com/php-fig/container",
+            "keywords": [
+                "PSR-11",
+                "container",
+                "container-interface",
+                "container-interop",
+                "psr"
+            ],
+            "support": {
+                "issues": "https://github.com/php-fig/container/issues",
+                "source": "https://github.com/php-fig/container/tree/1.1.2"
+            },
+            "time": "2021-11-05T16:50:12+00:00"
+        },
+        {
+            "name": "psr/event-dispatcher",
+            "version": "1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/event-dispatcher.git",
+                "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0",
+                "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\EventDispatcher\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Standard interfaces for event handling.",
+            "keywords": [
+                "events",
+                "psr",
+                "psr-14"
+            ],
+            "support": {
+                "issues": "https://github.com/php-fig/event-dispatcher/issues",
+                "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0"
+            },
+            "time": "2019-01-08T18:20:26+00:00"
+        },
+        {
+            "name": "psr/log",
+            "version": "1.1.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/log.git",
+                "reference": "d49695b909c3b7628b6289db5479a1c204601f11"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
+                "reference": "d49695b909c3b7628b6289db5479a1c204601f11",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.1.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Log\\": "Psr/Log/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "https://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for logging libraries",
+            "homepage": "https://github.com/php-fig/log",
+            "keywords": [
+                "log",
+                "psr",
+                "psr-3"
+            ],
+            "support": {
+                "source": "https://github.com/php-fig/log/tree/1.1.4"
+            },
+            "time": "2021-05-03T11:20:27+00:00"
+        },
+        {
+            "name": "psr/simple-cache",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/simple-cache.git",
+                "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
+                "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\SimpleCache\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interfaces for simple caching",
+            "keywords": [
+                "cache",
+                "caching",
+                "psr",
+                "psr-16",
+                "simple-cache"
+            ],
+            "support": {
+                "source": "https://github.com/php-fig/simple-cache/tree/master"
+            },
+            "time": "2017-10-23T01:57:42+00:00"
+        },
+        {
+            "name": "react/promise",
+            "version": "v2.9.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/reactphp/promise.git",
+                "reference": "234f8fd1023c9158e2314fa9d7d0e6a83db42910"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/reactphp/promise/zipball/234f8fd1023c9158e2314fa9d7d0e6a83db42910",
+                "reference": "234f8fd1023c9158e2314fa9d7d0e6a83db42910",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.4.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.36"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "src/functions_include.php"
+                ],
+                "psr-4": {
+                    "React\\Promise\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jan Sorgalla",
+                    "email": "jsorgalla@gmail.com",
+                    "homepage": "https://sorgalla.com/"
+                },
+                {
+                    "name": "Christian Lück",
+                    "email": "christian@clue.engineering",
+                    "homepage": "https://clue.engineering/"
+                },
+                {
+                    "name": "Cees-Jan Kiewiet",
+                    "email": "reactphp@ceesjankiewiet.nl",
+                    "homepage": "https://wyrihaximus.net/"
+                },
+                {
+                    "name": "Chris Boden",
+                    "email": "cboden@gmail.com",
+                    "homepage": "https://cboden.dev/"
+                }
+            ],
+            "description": "A lightweight implementation of CommonJS Promises/A for PHP",
+            "keywords": [
+                "promise",
+                "promises"
+            ],
+            "support": {
+                "issues": "https://github.com/reactphp/promise/issues",
+                "source": "https://github.com/reactphp/promise/tree/v2.9.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/WyriHaximus",
+                    "type": "github"
+                },
+                {
+                    "url": "https://github.com/clue",
+                    "type": "github"
+                }
+            ],
+            "time": "2022-02-11T10:27:51+00:00"
+        },
+        {
+            "name": "robrichards/xmlseclibs",
+            "version": "3.1.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/robrichards/xmlseclibs.git",
+                "reference": "f8f19e58f26cdb42c54b214ff8a820760292f8df"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/robrichards/xmlseclibs/zipball/f8f19e58f26cdb42c54b214ff8a820760292f8df",
+                "reference": "f8f19e58f26cdb42c54b214ff8a820760292f8df",
+                "shasum": ""
+            },
+            "require": {
+                "ext-openssl": "*",
+                "php": ">= 5.4"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "RobRichards\\XMLSecLibs\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "description": "A PHP library for XML Security",
+            "homepage": "https://github.com/robrichards/xmlseclibs",
+            "keywords": [
+                "security",
+                "signature",
+                "xml",
+                "xmldsig"
+            ],
+            "support": {
+                "issues": "https://github.com/robrichards/xmlseclibs/issues",
+                "source": "https://github.com/robrichards/xmlseclibs/tree/3.1.1"
+            },
+            "time": "2020-09-05T13:00:25+00:00"
+        },
+        {
+            "name": "seld/jsonlint",
+            "version": "1.9.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/Seldaek/jsonlint.git",
+                "reference": "4211420d25eba80712bff236a98960ef68b866b7"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/4211420d25eba80712bff236a98960ef68b866b7",
+                "reference": "4211420d25eba80712bff236a98960ef68b866b7",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.3 || ^7.0 || ^8.0"
+            },
+            "require-dev": {
+                "phpstan/phpstan": "^1.5",
+                "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^8.5.13"
+            },
+            "bin": [
+                "bin/jsonlint"
+            ],
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Seld\\JsonLint\\": "src/Seld/JsonLint/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jordi Boggiano",
+                    "email": "j.boggiano@seld.be",
+                    "homepage": "http://seld.be"
+                }
+            ],
+            "description": "JSON Linter",
+            "keywords": [
+                "json",
+                "linter",
+                "parser",
+                "validator"
+            ],
+            "support": {
+                "issues": "https://github.com/Seldaek/jsonlint/issues",
+                "source": "https://github.com/Seldaek/jsonlint/tree/1.9.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/Seldaek",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/seld/jsonlint",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-04-01T13:37:23+00:00"
+        },
+        {
+            "name": "seld/phar-utils",
+            "version": "1.2.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/Seldaek/phar-utils.git",
+                "reference": "ea2f4014f163c1be4c601b9b7bd6af81ba8d701c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/ea2f4014f163c1be4c601b9b7bd6af81ba8d701c",
+                "reference": "ea2f4014f163c1be4c601b9b7bd6af81ba8d701c",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Seld\\PharUtils\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jordi Boggiano",
+                    "email": "j.boggiano@seld.be"
+                }
+            ],
+            "description": "PHAR file format utilities, for when PHP phars you up",
+            "keywords": [
+                "phar"
+            ],
+            "support": {
+                "issues": "https://github.com/Seldaek/phar-utils/issues",
+                "source": "https://github.com/Seldaek/phar-utils/tree/1.2.1"
+            },
+            "time": "2022-08-31T10:31:18+00:00"
+        },
+        {
+            "name": "seld/signal-handler",
+            "version": "2.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/Seldaek/signal-handler.git",
+                "reference": "f69d119511dc0360440cdbdaa71829c149b7be75"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/Seldaek/signal-handler/zipball/f69d119511dc0360440cdbdaa71829c149b7be75",
+                "reference": "f69d119511dc0360440cdbdaa71829c149b7be75",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.0"
+            },
+            "require-dev": {
+                "phpstan/phpstan": "^1",
+                "phpstan/phpstan-deprecation-rules": "^1.0",
+                "phpstan/phpstan-phpunit": "^1",
+                "phpstan/phpstan-strict-rules": "^1.3",
+                "phpunit/phpunit": "^7.5.20 || ^8.5.23",
+                "psr/log": "^1 || ^2 || ^3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "2.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Seld\\Signal\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jordi Boggiano",
+                    "email": "j.boggiano@seld.be",
+                    "homepage": "http://seld.be"
+                }
+            ],
+            "description": "Simple unix signal handler that silently fails where signals are not supported for easy cross-platform development",
+            "keywords": [
+                "posix",
+                "sigint",
+                "signal",
+                "sigterm",
+                "unix"
+            ],
+            "support": {
+                "issues": "https://github.com/Seldaek/signal-handler/issues",
+                "source": "https://github.com/Seldaek/signal-handler/tree/2.0.1"
+            },
+            "time": "2022-07-20T18:31:45+00:00"
+        },
+        {
+            "name": "simplesamlphp/assert",
+            "version": "v0.8.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/simplesamlphp/assert.git",
+                "reference": "d3b0f38f4ae083822471c15e3c4a0401ddaeac73"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/simplesamlphp/assert/zipball/d3b0f38f4ae083822471c15e3c4a0401ddaeac73",
+                "reference": "d3b0f38f4ae083822471c15e3c4a0401ddaeac73",
+                "shasum": ""
+            },
+            "require": {
+                "ext-spl": "*",
+                "php": "^7.4 || ^8.0",
+                "webmozart/assert": "^1.11"
+            },
+            "require-dev": {
+                "simplesamlphp/simplesamlphp-test-framework": "^1.2.1"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "v0.8.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "SimpleSAML\\Assert\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "LGPL-2.1-or-later"
+            ],
+            "authors": [
+                {
+                    "name": "Tim van Dijen",
+                    "email": "tvdijen@gmail.com"
+                },
+                {
+                    "name": "Jaime Perez Crespo",
+                    "email": "jaimepc@gmail.com"
+                }
+            ],
+            "description": "A wrapper around webmozart/assert to make it useful beyond checking method arguments",
+            "support": {
+                "issues": "https://github.com/simplesamlphp/assert/issues",
+                "source": "https://github.com/simplesamlphp/assert/tree/v0.8.0"
+            },
+            "time": "2022-09-20T20:18:55+00:00"
+        },
+        {
+            "name": "simplesamlphp/composer-module-installer",
+            "version": "v1.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/simplesamlphp/composer-module-installer.git",
+                "reference": "27b4fe96198ffaff3ab49c87b40f4cb24de77b01"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/simplesamlphp/composer-module-installer/zipball/27b4fe96198ffaff3ab49c87b40f4cb24de77b01",
+                "reference": "27b4fe96198ffaff3ab49c87b40f4cb24de77b01",
+                "shasum": ""
+            },
+            "require": {
+                "composer-plugin-api": "^1.1 || ^2.0",
+                "php": "^7.4 || ^8.0",
+                "simplesamlphp/simplesamlphp": "*"
+            },
+            "type": "composer-plugin",
+            "extra": {
+                "class": "SimpleSAML\\Composer\\ModuleInstallerPlugin"
+            },
+            "autoload": {
+                "psr-4": {
+                    "SimpleSAML\\Composer\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "LGPL-2.1-only"
+            ],
+            "description": "A Composer plugin that allows installing SimpleSAMLphp modules through Composer.",
+            "support": {
+                "issues": "https://github.com/simplesamlphp/composer-module-installer/issues",
+                "source": "https://github.com/simplesamlphp/composer-module-installer/tree/v1.2.0"
+            },
+            "time": "2022-08-31T17:20:27+00:00"
+        },
+        {
+            "name": "simplesamlphp/saml2",
+            "version": "v4.6.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/simplesamlphp/saml2.git",
+                "reference": "bfc9c79dd6b728a41d1de988f545f6e64728a51d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/simplesamlphp/saml2/zipball/bfc9c79dd6b728a41d1de988f545f6e64728a51d",
+                "reference": "bfc9c79dd6b728a41d1de988f545f6e64728a51d",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "ext-openssl": "*",
+                "ext-zlib": "*",
+                "php": ">=7.1 || ^8.0",
+                "psr/log": "~1.1 || ^2.0 || ^3.0",
+                "robrichards/xmlseclibs": "^3.1.1",
+                "webmozart/assert": "^1.9"
+            },
+            "require-dev": {
+                "mockery/mockery": "^1.3",
+                "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
+                "sebastian/phpcpd": "~4.1 || ^5.0 || ^6.0",
+                "simplesamlphp/simplesamlphp-test-framework": "~0.1.0",
+                "squizlabs/php_codesniffer": "~3.5"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "v4.2.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "SAML2\\": "src/SAML2"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "LGPL-2.1-or-later"
+            ],
+            "authors": [
+                {
+                    "name": "Andreas Åkre Solberg",
+                    "email": "andreas.solberg@uninett.no"
+                }
+            ],
+            "description": "SAML2 PHP library from SimpleSAMLphp",
+            "support": {
+                "issues": "https://github.com/simplesamlphp/saml2/issues",
+                "source": "https://github.com/simplesamlphp/saml2/tree/v4.6.3"
+            },
+            "time": "2022-06-13T14:04:10+00:00"
+        },
+        {
+            "name": "simplesamlphp/simplesamlphp",
+            "version": "v2.0.0-rc2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/simplesamlphp/simplesamlphp.git",
+                "reference": "2cf4ec863ab9aa59eb4ad0b5287ab8ab97360089"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/simplesamlphp/simplesamlphp/zipball/2cf4ec863ab9aa59eb4ad0b5287ab8ab97360089",
+                "reference": "2cf4ec863ab9aa59eb4ad0b5287ab8ab97360089",
+                "shasum": ""
+            },
+            "require": {
+                "composer/composer": "^2.3",
+                "ext-date": "*",
+                "ext-dom": "*",
+                "ext-hash": "*",
+                "ext-intl": "*",
+                "ext-json": "*",
+                "ext-mbstring": "*",
+                "ext-openssl": "*",
+                "ext-pcre": "*",
+                "ext-spl": "*",
+                "ext-zlib": "*",
+                "gettext/gettext": "^5.6.1",
+                "gettext/translator": "^1.0.1",
+                "php": ">=7.4 || ^8.0",
+                "phpmailer/phpmailer": "^6.5",
+                "simplesamlphp/assert": "^0.8.0",
+                "simplesamlphp/saml2": "^4.6",
+                "symfony/cache": "^5.4",
+                "symfony/config": "^5.4",
+                "symfony/console": "^5.4",
+                "symfony/dependency-injection": "^5.4",
+                "symfony/filesystem": "^5.4",
+                "symfony/finder": "^5.4",
+                "symfony/framework-bundle": "^5.4",
+                "symfony/http-foundation": "^5.4",
+                "symfony/http-kernel": "^5.4",
+                "symfony/intl": "^5.4",
+                "symfony/routing": "^5.4",
+                "symfony/translation-contracts": "^2.5",
+                "symfony/twig-bridge": "^5.4",
+                "symfony/var-exporter": "^5.4",
+                "symfony/yaml": "^5.4",
+                "twig/intl-extra": "^3.3",
+                "twig/twig": "^3.3.8"
+            },
+            "require-dev": {
+                "ext-curl": "*",
+                "ext-pdo_sqlite": "*",
+                "mikey179/vfsstream": "~1.6",
+                "simplesamlphp/simplesamlphp-module-adfs": ">=2.0.0-rc5",
+                "simplesamlphp/simplesamlphp-test-framework": "^1.2.1",
+                "simplesamlphp/xml-security": "^0.6.6"
+            },
+            "suggest": {
+                "ext-curl": "Needed in order to check for updates automatically",
+                "ext-ldap": "Needed if an LDAP backend is used",
+                "ext-memcache": "Needed if a Memcache server is used to store session information",
+                "ext-mysql": "Needed if a MySQL backend is used, either for authentication or to store session information",
+                "ext-pdo": "Needed if a database backend is used, either for authentication or to store session information",
+                "ext-pgsql": "Needed if a PostgreSQL backend is used, either for authentication or to store session information",
+                "predis/predis": "Needed if a Redis server is used to store session information"
+            },
+            "type": "project",
+            "autoload": {
+                "files": [
+                    "src/_autoload_modules.php"
+                ],
+                "psr-4": {
+                    "SimpleSAML\\": "src/SimpleSAML",
+                    "SimpleSAML\\Module\\core\\": "modules/core/src",
+                    "SimpleSAML\\Module\\cron\\": "modules/cron/src",
+                    "SimpleSAML\\Module\\saml\\": "modules/saml/src",
+                    "SimpleSAML\\Module\\admin\\": "modules/admin/src",
+                    "SimpleSAML\\Module\\multiauth\\": "modules/multiauth/src",
+                    "SimpleSAML\\Module\\exampleauth\\": "modules/exampleauth/src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "LGPL-2.1-or-later"
+            ],
+            "authors": [
+                {
+                    "name": "Andreas Åkre Solberg",
+                    "email": "andreas.solberg@uninett.no"
+                },
+                {
+                    "name": "Olav Morken",
+                    "email": "olav.morken@uninett.no"
+                },
+                {
+                    "name": "Jaime Perez",
+                    "email": "jaime.perez@uninett.no"
+                }
+            ],
+            "description": "A PHP implementation of a SAML 2.0 service provider and identity provider.",
+            "homepage": "http://simplesamlphp.org",
+            "keywords": [
+                "SAML2",
+                "idp",
+                "oauth",
+                "shibboleth",
+                "sp",
+                "ws-federation"
+            ],
+            "support": {
+                "issues": "https://github.com/simplesamlphp/simplesamlphp/issues",
+                "source": "https://github.com/simplesamlphp/simplesamlphp"
+            },
+            "time": "2022-09-22T06:38:05+00:00"
+        },
+        {
+            "name": "symfony/cache",
+            "version": "v5.4.11",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/cache.git",
+                "reference": "5a0fff46df349f0db3fe242263451fddf5277362"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/cache/zipball/5a0fff46df349f0db3fe242263451fddf5277362",
+                "reference": "5a0fff46df349f0db3fe242263451fddf5277362",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "psr/cache": "^1.0|^2.0",
+                "psr/log": "^1.1|^2|^3",
+                "symfony/cache-contracts": "^1.1.7|^2",
+                "symfony/deprecation-contracts": "^2.1|^3",
+                "symfony/polyfill-php73": "^1.9",
+                "symfony/polyfill-php80": "^1.16",
+                "symfony/service-contracts": "^1.1|^2|^3",
+                "symfony/var-exporter": "^4.4|^5.0|^6.0"
+            },
+            "conflict": {
+                "doctrine/dbal": "<2.13.1",
+                "symfony/dependency-injection": "<4.4",
+                "symfony/http-kernel": "<4.4",
+                "symfony/var-dumper": "<4.4"
+            },
+            "provide": {
+                "psr/cache-implementation": "1.0|2.0",
+                "psr/simple-cache-implementation": "1.0|2.0",
+                "symfony/cache-implementation": "1.0|2.0"
+            },
+            "require-dev": {
+                "cache/integration-tests": "dev-master",
+                "doctrine/cache": "^1.6|^2.0",
+                "doctrine/dbal": "^2.13.1|^3.0",
+                "predis/predis": "^1.1",
+                "psr/simple-cache": "^1.0|^2.0",
+                "symfony/config": "^4.4|^5.0|^6.0",
+                "symfony/dependency-injection": "^4.4|^5.0|^6.0",
+                "symfony/filesystem": "^4.4|^5.0|^6.0",
+                "symfony/http-kernel": "^4.4|^5.0|^6.0",
+                "symfony/messenger": "^4.4|^5.0|^6.0",
+                "symfony/var-dumper": "^4.4|^5.0|^6.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Cache\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Provides an extended PSR-6, PSR-16 (and tags) implementation",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "caching",
+                "psr6"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/cache/tree/v5.4.11"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-07-28T15:25:17+00:00"
+        },
+        {
+            "name": "symfony/cache-contracts",
+            "version": "v2.5.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/cache-contracts.git",
+                "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/64be4a7acb83b6f2bf6de9a02cee6dad41277ebc",
+                "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "psr/cache": "^1.0|^2.0|^3.0"
+            },
+            "suggest": {
+                "symfony/cache-implementation": ""
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "2.5-dev"
+                },
+                "thanks": {
+                    "name": "symfony/contracts",
+                    "url": "https://github.com/symfony/contracts"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Contracts\\Cache\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Generic abstractions related to caching",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "abstractions",
+                "contracts",
+                "decoupling",
+                "interfaces",
+                "interoperability",
+                "standards"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/cache-contracts/tree/v2.5.2"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-01-02T09:53:40+00:00"
+        },
+        {
+            "name": "symfony/config",
+            "version": "v5.4.11",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/config.git",
+                "reference": "ec79e03125c1d2477e43dde8528535d90cc78379"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/config/zipball/ec79e03125c1d2477e43dde8528535d90cc78379",
+                "reference": "ec79e03125c1d2477e43dde8528535d90cc78379",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "symfony/deprecation-contracts": "^2.1|^3",
+                "symfony/filesystem": "^4.4|^5.0|^6.0",
+                "symfony/polyfill-ctype": "~1.8",
+                "symfony/polyfill-php80": "^1.16",
+                "symfony/polyfill-php81": "^1.22"
+            },
+            "conflict": {
+                "symfony/finder": "<4.4"
+            },
+            "require-dev": {
+                "symfony/event-dispatcher": "^4.4|^5.0|^6.0",
+                "symfony/finder": "^4.4|^5.0|^6.0",
+                "symfony/messenger": "^4.4|^5.0|^6.0",
+                "symfony/service-contracts": "^1.1|^2|^3",
+                "symfony/yaml": "^4.4|^5.0|^6.0"
+            },
+            "suggest": {
+                "symfony/yaml": "To use the yaml reference dumper"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Config\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Helps you find, load, combine, autofill and validate configuration values of any kind",
+            "homepage": "https://symfony.com",
+            "support": {
+                "source": "https://github.com/symfony/config/tree/v5.4.11"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-07-20T13:00:38+00:00"
+        },
+        {
+            "name": "symfony/console",
+            "version": "v5.4.12",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/console.git",
+                "reference": "c072aa8f724c3af64e2c7a96b796a4863d24dba1"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/console/zipball/c072aa8f724c3af64e2c7a96b796a4863d24dba1",
+                "reference": "c072aa8f724c3af64e2c7a96b796a4863d24dba1",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "symfony/deprecation-contracts": "^2.1|^3",
+                "symfony/polyfill-mbstring": "~1.0",
+                "symfony/polyfill-php73": "^1.9",
+                "symfony/polyfill-php80": "^1.16",
+                "symfony/service-contracts": "^1.1|^2|^3",
+                "symfony/string": "^5.1|^6.0"
+            },
+            "conflict": {
+                "psr/log": ">=3",
+                "symfony/dependency-injection": "<4.4",
+                "symfony/dotenv": "<5.1",
+                "symfony/event-dispatcher": "<4.4",
+                "symfony/lock": "<4.4",
+                "symfony/process": "<4.4"
+            },
+            "provide": {
+                "psr/log-implementation": "1.0|2.0"
+            },
+            "require-dev": {
+                "psr/log": "^1|^2",
+                "symfony/config": "^4.4|^5.0|^6.0",
+                "symfony/dependency-injection": "^4.4|^5.0|^6.0",
+                "symfony/event-dispatcher": "^4.4|^5.0|^6.0",
+                "symfony/lock": "^4.4|^5.0|^6.0",
+                "symfony/process": "^4.4|^5.0|^6.0",
+                "symfony/var-dumper": "^4.4|^5.0|^6.0"
+            },
+            "suggest": {
+                "psr/log": "For using the console logger",
+                "symfony/event-dispatcher": "",
+                "symfony/lock": "",
+                "symfony/process": ""
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Console\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Eases the creation of beautiful and testable command line interfaces",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "cli",
+                "command line",
+                "console",
+                "terminal"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/console/tree/v5.4.12"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-08-17T13:18:05+00:00"
+        },
+        {
+            "name": "symfony/dependency-injection",
+            "version": "v5.4.11",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/dependency-injection.git",
+                "reference": "a8b9251016e9476db73e25fa836904bc0bf74c62"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/a8b9251016e9476db73e25fa836904bc0bf74c62",
+                "reference": "a8b9251016e9476db73e25fa836904bc0bf74c62",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "psr/container": "^1.1.1",
+                "symfony/deprecation-contracts": "^2.1|^3",
+                "symfony/polyfill-php80": "^1.16",
+                "symfony/polyfill-php81": "^1.22",
+                "symfony/service-contracts": "^1.1.6|^2"
+            },
+            "conflict": {
+                "ext-psr": "<1.1|>=2",
+                "symfony/config": "<5.3",
+                "symfony/finder": "<4.4",
+                "symfony/proxy-manager-bridge": "<4.4",
+                "symfony/yaml": "<4.4.26"
+            },
+            "provide": {
+                "psr/container-implementation": "1.0",
+                "symfony/service-implementation": "1.0|2.0"
+            },
+            "require-dev": {
+                "symfony/config": "^5.3|^6.0",
+                "symfony/expression-language": "^4.4|^5.0|^6.0",
+                "symfony/yaml": "^4.4.26|^5.0|^6.0"
+            },
+            "suggest": {
+                "symfony/config": "",
+                "symfony/expression-language": "For using expressions in service container configuration",
+                "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required",
+                "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them",
+                "symfony/yaml": ""
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\DependencyInjection\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Allows you to standardize and centralize the way objects are constructed in your application",
+            "homepage": "https://symfony.com",
+            "support": {
+                "source": "https://github.com/symfony/dependency-injection/tree/v5.4.11"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-07-20T13:00:38+00:00"
+        },
+        {
+            "name": "symfony/deprecation-contracts",
+            "version": "v2.5.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/deprecation-contracts.git",
+                "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
+                "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "2.5-dev"
+                },
+                "thanks": {
+                    "name": "symfony/contracts",
+                    "url": "https://github.com/symfony/contracts"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "function.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "A generic function and convention to trigger deprecation notices",
+            "homepage": "https://symfony.com",
+            "support": {
+                "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-01-02T09:53:40+00:00"
+        },
+        {
+            "name": "symfony/error-handler",
+            "version": "v5.4.11",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/error-handler.git",
+                "reference": "f75d17cb4769eb38cd5fccbda95cd80a054d35c8"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/error-handler/zipball/f75d17cb4769eb38cd5fccbda95cd80a054d35c8",
+                "reference": "f75d17cb4769eb38cd5fccbda95cd80a054d35c8",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "psr/log": "^1|^2|^3",
+                "symfony/var-dumper": "^4.4|^5.0|^6.0"
+            },
+            "require-dev": {
+                "symfony/deprecation-contracts": "^2.1|^3",
+                "symfony/http-kernel": "^4.4|^5.0|^6.0",
+                "symfony/serializer": "^4.4|^5.0|^6.0"
+            },
+            "bin": [
+                "Resources/bin/patch-type-declarations"
+            ],
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\ErrorHandler\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Provides tools to manage errors and ease debugging PHP code",
+            "homepage": "https://symfony.com",
+            "support": {
+                "source": "https://github.com/symfony/error-handler/tree/v5.4.11"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-07-29T07:37:50+00:00"
+        },
+        {
+            "name": "symfony/event-dispatcher",
+            "version": "v5.4.9",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/event-dispatcher.git",
+                "reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc",
+                "reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "symfony/deprecation-contracts": "^2.1|^3",
+                "symfony/event-dispatcher-contracts": "^2|^3",
+                "symfony/polyfill-php80": "^1.16"
+            },
+            "conflict": {
+                "symfony/dependency-injection": "<4.4"
+            },
+            "provide": {
+                "psr/event-dispatcher-implementation": "1.0",
+                "symfony/event-dispatcher-implementation": "2.0"
+            },
+            "require-dev": {
+                "psr/log": "^1|^2|^3",
+                "symfony/config": "^4.4|^5.0|^6.0",
+                "symfony/dependency-injection": "^4.4|^5.0|^6.0",
+                "symfony/error-handler": "^4.4|^5.0|^6.0",
+                "symfony/expression-language": "^4.4|^5.0|^6.0",
+                "symfony/http-foundation": "^4.4|^5.0|^6.0",
+                "symfony/service-contracts": "^1.1|^2|^3",
+                "symfony/stopwatch": "^4.4|^5.0|^6.0"
+            },
+            "suggest": {
+                "symfony/dependency-injection": "",
+                "symfony/http-kernel": ""
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\EventDispatcher\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
+            "homepage": "https://symfony.com",
+            "support": {
+                "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.9"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-05-05T16:45:39+00:00"
+        },
+        {
+            "name": "symfony/event-dispatcher-contracts",
+            "version": "v2.5.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/event-dispatcher-contracts.git",
+                "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f98b54df6ad059855739db6fcbc2d36995283fe1",
+                "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "psr/event-dispatcher": "^1"
+            },
+            "suggest": {
+                "symfony/event-dispatcher-implementation": ""
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "2.5-dev"
+                },
+                "thanks": {
+                    "name": "symfony/contracts",
+                    "url": "https://github.com/symfony/contracts"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Contracts\\EventDispatcher\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Generic abstractions related to dispatching event",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "abstractions",
+                "contracts",
+                "decoupling",
+                "interfaces",
+                "interoperability",
+                "standards"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.2"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-01-02T09:53:40+00:00"
+        },
+        {
+            "name": "symfony/filesystem",
+            "version": "v5.4.12",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/filesystem.git",
+                "reference": "2d67c1f9a1937406a9be3171b4b22250c0a11447"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/filesystem/zipball/2d67c1f9a1937406a9be3171b4b22250c0a11447",
+                "reference": "2d67c1f9a1937406a9be3171b4b22250c0a11447",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "symfony/polyfill-ctype": "~1.8",
+                "symfony/polyfill-mbstring": "~1.8",
+                "symfony/polyfill-php80": "^1.16"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Filesystem\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Provides basic utilities for the filesystem",
+            "homepage": "https://symfony.com",
+            "support": {
+                "source": "https://github.com/symfony/filesystem/tree/v5.4.12"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-08-02T13:48:16+00:00"
+        },
+        {
+            "name": "symfony/finder",
+            "version": "v5.4.11",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/finder.git",
+                "reference": "7872a66f57caffa2916a584db1aa7f12adc76f8c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/finder/zipball/7872a66f57caffa2916a584db1aa7f12adc76f8c",
+                "reference": "7872a66f57caffa2916a584db1aa7f12adc76f8c",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "symfony/deprecation-contracts": "^2.1|^3",
+                "symfony/polyfill-php80": "^1.16"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Finder\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Finds files and directories via an intuitive fluent interface",
+            "homepage": "https://symfony.com",
+            "support": {
+                "source": "https://github.com/symfony/finder/tree/v5.4.11"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-07-29T07:37:50+00:00"
+        },
+        {
+            "name": "symfony/framework-bundle",
+            "version": "v5.4.12",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/framework-bundle.git",
+                "reference": "49f8fe5d39b7513a3f26898788885dbe66b0d910"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/49f8fe5d39b7513a3f26898788885dbe66b0d910",
+                "reference": "49f8fe5d39b7513a3f26898788885dbe66b0d910",
+                "shasum": ""
+            },
+            "require": {
+                "ext-xml": "*",
+                "php": ">=7.2.5",
+                "symfony/cache": "^5.2|^6.0",
+                "symfony/config": "^5.3|^6.0",
+                "symfony/dependency-injection": "^5.4.5|^6.0.5",
+                "symfony/deprecation-contracts": "^2.1|^3",
+                "symfony/error-handler": "^4.4.1|^5.0.1|^6.0",
+                "symfony/event-dispatcher": "^5.1|^6.0",
+                "symfony/filesystem": "^4.4|^5.0|^6.0",
+                "symfony/finder": "^4.4|^5.0|^6.0",
+                "symfony/http-foundation": "^5.3|^6.0",
+                "symfony/http-kernel": "^5.4|^6.0",
+                "symfony/polyfill-mbstring": "~1.0",
+                "symfony/polyfill-php80": "^1.16",
+                "symfony/polyfill-php81": "^1.22",
+                "symfony/routing": "^5.3|^6.0"
+            },
+            "conflict": {
+                "doctrine/annotations": "<1.13.1",
+                "doctrine/cache": "<1.11",
+                "doctrine/persistence": "<1.3",
+                "phpdocumentor/reflection-docblock": "<3.2.2",
+                "phpdocumentor/type-resolver": "<1.4.0",
+                "phpunit/phpunit": "<5.4.3",
+                "symfony/asset": "<5.3",
+                "symfony/console": "<5.2.5",
+                "symfony/dom-crawler": "<4.4",
+                "symfony/dotenv": "<5.1",
+                "symfony/form": "<5.2",
+                "symfony/http-client": "<4.4",
+                "symfony/lock": "<4.4",
+                "symfony/mailer": "<5.2",
+                "symfony/messenger": "<5.4",
+                "symfony/mime": "<4.4",
+                "symfony/property-access": "<5.3",
+                "symfony/property-info": "<4.4",
+                "symfony/security-csrf": "<5.3",
+                "symfony/serializer": "<5.2",
+                "symfony/service-contracts": ">=3.0",
+                "symfony/stopwatch": "<4.4",
+                "symfony/translation": "<5.3",
+                "symfony/twig-bridge": "<4.4",
+                "symfony/twig-bundle": "<4.4",
+                "symfony/validator": "<5.2",
+                "symfony/web-profiler-bundle": "<4.4",
+                "symfony/workflow": "<5.2"
+            },
+            "require-dev": {
+                "doctrine/annotations": "^1.13.1",
+                "doctrine/cache": "^1.11|^2.0",
+                "doctrine/persistence": "^1.3|^2|^3",
+                "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
+                "symfony/asset": "^5.3|^6.0",
+                "symfony/browser-kit": "^5.4|^6.0",
+                "symfony/console": "^5.4.9|^6.0.9",
+                "symfony/css-selector": "^4.4|^5.0|^6.0",
+                "symfony/dom-crawler": "^4.4.30|^5.3.7|^6.0",
+                "symfony/dotenv": "^5.1|^6.0",
+                "symfony/expression-language": "^4.4|^5.0|^6.0",
+                "symfony/form": "^5.2|^6.0",
+                "symfony/http-client": "^4.4|^5.0|^6.0",
+                "symfony/lock": "^4.4|^5.0|^6.0",
+                "symfony/mailer": "^5.2|^6.0",
+                "symfony/messenger": "^5.4|^6.0",
+                "symfony/mime": "^4.4|^5.0|^6.0",
+                "symfony/notifier": "^5.4|^6.0",
+                "symfony/polyfill-intl-icu": "~1.0",
+                "symfony/process": "^4.4|^5.0|^6.0",
+                "symfony/property-info": "^4.4|^5.0|^6.0",
+                "symfony/rate-limiter": "^5.2|^6.0",
+                "symfony/security-bundle": "^5.4|^6.0",
+                "symfony/serializer": "^5.4|^6.0",
+                "symfony/stopwatch": "^4.4|^5.0|^6.0",
+                "symfony/string": "^5.0|^6.0",
+                "symfony/translation": "^5.3|^6.0",
+                "symfony/twig-bundle": "^4.4|^5.0|^6.0",
+                "symfony/validator": "^5.2|^6.0",
+                "symfony/web-link": "^4.4|^5.0|^6.0",
+                "symfony/workflow": "^5.2|^6.0",
+                "symfony/yaml": "^4.4|^5.0|^6.0",
+                "twig/twig": "^2.10|^3.0"
+            },
+            "suggest": {
+                "ext-apcu": "For best performance of the system caches",
+                "symfony/console": "For using the console commands",
+                "symfony/form": "For using forms",
+                "symfony/property-info": "For using the property_info service",
+                "symfony/serializer": "For using the serializer service",
+                "symfony/validator": "For using validation",
+                "symfony/web-link": "For using web links, features such as preloading, prefetching or prerendering",
+                "symfony/yaml": "For using the debug:config and lint:yaml commands"
+            },
+            "type": "symfony-bundle",
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Bundle\\FrameworkBundle\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework",
+            "homepage": "https://symfony.com",
+            "support": {
+                "source": "https://github.com/symfony/framework-bundle/tree/v5.4.12"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-08-26T10:32:10+00:00"
+        },
+        {
+            "name": "symfony/http-foundation",
+            "version": "v5.4.12",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/http-foundation.git",
+                "reference": "f4bfe9611b113b15d98a43da68ec9b5a00d56791"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/http-foundation/zipball/f4bfe9611b113b15d98a43da68ec9b5a00d56791",
+                "reference": "f4bfe9611b113b15d98a43da68ec9b5a00d56791",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "symfony/deprecation-contracts": "^2.1|^3",
+                "symfony/polyfill-mbstring": "~1.1",
+                "symfony/polyfill-php80": "^1.16"
+            },
+            "require-dev": {
+                "predis/predis": "~1.0",
+                "symfony/cache": "^4.4|^5.0|^6.0",
+                "symfony/dependency-injection": "^5.4|^6.0",
+                "symfony/expression-language": "^4.4|^5.0|^6.0",
+                "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4",
+                "symfony/mime": "^4.4|^5.0|^6.0",
+                "symfony/rate-limiter": "^5.2|^6.0"
+            },
+            "suggest": {
+                "symfony/mime": "To use the file extension guesser"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\HttpFoundation\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Defines an object-oriented layer for the HTTP specification",
+            "homepage": "https://symfony.com",
+            "support": {
+                "source": "https://github.com/symfony/http-foundation/tree/v5.4.12"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-08-19T07:33:17+00:00"
+        },
+        {
+            "name": "symfony/http-kernel",
+            "version": "v5.4.12",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/http-kernel.git",
+                "reference": "37f660fa3bcd78fe4893ce23ebe934618ec099be"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/http-kernel/zipball/37f660fa3bcd78fe4893ce23ebe934618ec099be",
+                "reference": "37f660fa3bcd78fe4893ce23ebe934618ec099be",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "psr/log": "^1|^2",
+                "symfony/deprecation-contracts": "^2.1|^3",
+                "symfony/error-handler": "^4.4|^5.0|^6.0",
+                "symfony/event-dispatcher": "^5.0|^6.0",
+                "symfony/http-foundation": "^5.3.7|^6.0",
+                "symfony/polyfill-ctype": "^1.8",
+                "symfony/polyfill-php73": "^1.9",
+                "symfony/polyfill-php80": "^1.16"
+            },
+            "conflict": {
+                "symfony/browser-kit": "<5.4",
+                "symfony/cache": "<5.0",
+                "symfony/config": "<5.0",
+                "symfony/console": "<4.4",
+                "symfony/dependency-injection": "<5.3",
+                "symfony/doctrine-bridge": "<5.0",
+                "symfony/form": "<5.0",
+                "symfony/http-client": "<5.0",
+                "symfony/mailer": "<5.0",
+                "symfony/messenger": "<5.0",
+                "symfony/translation": "<5.0",
+                "symfony/twig-bridge": "<5.0",
+                "symfony/validator": "<5.0",
+                "twig/twig": "<2.13"
+            },
+            "provide": {
+                "psr/log-implementation": "1.0|2.0"
+            },
+            "require-dev": {
+                "psr/cache": "^1.0|^2.0|^3.0",
+                "symfony/browser-kit": "^5.4|^6.0",
+                "symfony/config": "^5.0|^6.0",
+                "symfony/console": "^4.4|^5.0|^6.0",
+                "symfony/css-selector": "^4.4|^5.0|^6.0",
+                "symfony/dependency-injection": "^5.3|^6.0",
+                "symfony/dom-crawler": "^4.4|^5.0|^6.0",
+                "symfony/expression-language": "^4.4|^5.0|^6.0",
+                "symfony/finder": "^4.4|^5.0|^6.0",
+                "symfony/http-client-contracts": "^1.1|^2|^3",
+                "symfony/process": "^4.4|^5.0|^6.0",
+                "symfony/routing": "^4.4|^5.0|^6.0",
+                "symfony/stopwatch": "^4.4|^5.0|^6.0",
+                "symfony/translation": "^4.4|^5.0|^6.0",
+                "symfony/translation-contracts": "^1.1|^2|^3",
+                "twig/twig": "^2.13|^3.0.4"
+            },
+            "suggest": {
+                "symfony/browser-kit": "",
+                "symfony/config": "",
+                "symfony/console": "",
+                "symfony/dependency-injection": ""
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\HttpKernel\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Provides a structured process for converting a Request into a Response",
+            "homepage": "https://symfony.com",
+            "support": {
+                "source": "https://github.com/symfony/http-kernel/tree/v5.4.12"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-08-26T14:40:40+00:00"
+        },
+        {
+            "name": "symfony/intl",
+            "version": "v5.4.11",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/intl.git",
+                "reference": "d305c0c1d31b30b3876e041804c35e49e5f8a96e"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/intl/zipball/d305c0c1d31b30b3876e041804c35e49e5f8a96e",
+                "reference": "d305c0c1d31b30b3876e041804c35e49e5f8a96e",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "symfony/deprecation-contracts": "^2.1|^3",
+                "symfony/polyfill-php80": "^1.16"
+            },
+            "require-dev": {
+                "symfony/filesystem": "^4.4|^5.0|^6.0"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "Resources/functions.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Component\\Intl\\": ""
+                },
+                "classmap": [
+                    "Resources/stubs"
+                ],
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Bernhard Schussek",
+                    "email": "bschussek@gmail.com"
+                },
+                {
+                    "name": "Eriksen Costa",
+                    "email": "eriksen.costa@infranology.com.br"
+                },
+                {
+                    "name": "Igor Wiedler",
+                    "email": "igor@wiedler.ch"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Provides a PHP replacement layer for the C intl extension that includes additional data from the ICU library",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "i18n",
+                "icu",
+                "internationalization",
+                "intl",
+                "l10n",
+                "localization"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/intl/tree/v5.4.11"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-07-20T11:34:24+00:00"
+        },
+        {
+            "name": "symfony/polyfill-ctype",
+            "version": "v1.26.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-ctype.git",
+                "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4",
+                "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "provide": {
+                "ext-ctype": "*"
+            },
+            "suggest": {
+                "ext-ctype": "For best performance"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.26-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Polyfill\\Ctype\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Gert de Pagter",
+                    "email": "BackEndTea@gmail.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill for ctype functions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "ctype",
+                "polyfill",
+                "portable"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/polyfill-ctype/tree/v1.26.0"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-05-24T11:49:31+00:00"
+        },
+        {
+            "name": "symfony/polyfill-intl-grapheme",
+            "version": "v1.26.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-intl-grapheme.git",
+                "reference": "433d05519ce6990bf3530fba6957499d327395c2"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/433d05519ce6990bf3530fba6957499d327395c2",
+                "reference": "433d05519ce6990bf3530fba6957499d327395c2",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "suggest": {
+                "ext-intl": "For best performance"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.26-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Polyfill\\Intl\\Grapheme\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill for intl's grapheme_* functions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "grapheme",
+                "intl",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.26.0"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-05-24T11:49:31+00:00"
+        },
+        {
+            "name": "symfony/polyfill-intl-normalizer",
+            "version": "v1.26.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
+                "reference": "219aa369ceff116e673852dce47c3a41794c14bd"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd",
+                "reference": "219aa369ceff116e673852dce47c3a41794c14bd",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "suggest": {
+                "ext-intl": "For best performance"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.26-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Polyfill\\Intl\\Normalizer\\": ""
+                },
+                "classmap": [
+                    "Resources/stubs"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill for intl's Normalizer class and related functions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "intl",
+                "normalizer",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-05-24T11:49:31+00:00"
+        },
+        {
+            "name": "symfony/polyfill-mbstring",
+            "version": "v1.26.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-mbstring.git",
+                "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e",
+                "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "provide": {
+                "ext-mbstring": "*"
+            },
+            "suggest": {
+                "ext-mbstring": "For best performance"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.26-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Polyfill\\Mbstring\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill for the Mbstring extension",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "mbstring",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-05-24T11:49:31+00:00"
+        },
+        {
+            "name": "symfony/polyfill-php73",
+            "version": "v1.26.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-php73.git",
+                "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/e440d35fa0286f77fb45b79a03fedbeda9307e85",
+                "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.26-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Polyfill\\Php73\\": ""
+                },
+                "classmap": [
+                    "Resources/stubs"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/polyfill-php73/tree/v1.26.0"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-05-24T11:49:31+00:00"
+        },
+        {
+            "name": "symfony/polyfill-php80",
+            "version": "v1.26.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-php80.git",
+                "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace",
+                "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.26-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Polyfill\\Php80\\": ""
+                },
+                "classmap": [
+                    "Resources/stubs"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Ion Bazan",
+                    "email": "ion.bazan@gmail.com"
+                },
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-05-10T07:21:04+00:00"
+        },
+        {
+            "name": "symfony/polyfill-php81",
+            "version": "v1.26.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-php81.git",
+                "reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/13f6d1271c663dc5ae9fb843a8f16521db7687a1",
+                "reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.26-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Polyfill\\Php81\\": ""
+                },
+                "classmap": [
+                    "Resources/stubs"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/polyfill-php81/tree/v1.26.0"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-05-24T11:49:31+00:00"
+        },
+        {
+            "name": "symfony/process",
+            "version": "v5.4.11",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/process.git",
+                "reference": "6e75fe6874cbc7e4773d049616ab450eff537bf1"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/process/zipball/6e75fe6874cbc7e4773d049616ab450eff537bf1",
+                "reference": "6e75fe6874cbc7e4773d049616ab450eff537bf1",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "symfony/polyfill-php80": "^1.16"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Process\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Executes commands in sub-processes",
+            "homepage": "https://symfony.com",
+            "support": {
+                "source": "https://github.com/symfony/process/tree/v5.4.11"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-06-27T16:58:25+00:00"
+        },
+        {
+            "name": "symfony/routing",
+            "version": "v5.4.11",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/routing.git",
+                "reference": "3e01ccd9b2a3a4167ba2b3c53612762300300226"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/routing/zipball/3e01ccd9b2a3a4167ba2b3c53612762300300226",
+                "reference": "3e01ccd9b2a3a4167ba2b3c53612762300300226",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "symfony/deprecation-contracts": "^2.1|^3",
+                "symfony/polyfill-php80": "^1.16"
+            },
+            "conflict": {
+                "doctrine/annotations": "<1.12",
+                "symfony/config": "<5.3",
+                "symfony/dependency-injection": "<4.4",
+                "symfony/yaml": "<4.4"
+            },
+            "require-dev": {
+                "doctrine/annotations": "^1.12",
+                "psr/log": "^1|^2|^3",
+                "symfony/config": "^5.3|^6.0",
+                "symfony/dependency-injection": "^4.4|^5.0|^6.0",
+                "symfony/expression-language": "^4.4|^5.0|^6.0",
+                "symfony/http-foundation": "^4.4|^5.0|^6.0",
+                "symfony/yaml": "^4.4|^5.0|^6.0"
+            },
+            "suggest": {
+                "symfony/config": "For using the all-in-one router or any loader",
+                "symfony/expression-language": "For using expression matching",
+                "symfony/http-foundation": "For using a Symfony Request object",
+                "symfony/yaml": "For using the YAML loader"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Routing\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Maps an HTTP request to a set of configuration variables",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "router",
+                "routing",
+                "uri",
+                "url"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/routing/tree/v5.4.11"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-07-20T13:00:38+00:00"
+        },
+        {
+            "name": "symfony/service-contracts",
+            "version": "v2.5.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/service-contracts.git",
+                "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c",
+                "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "psr/container": "^1.1",
+                "symfony/deprecation-contracts": "^2.1|^3"
+            },
+            "conflict": {
+                "ext-psr": "<1.1|>=2"
+            },
+            "suggest": {
+                "symfony/service-implementation": ""
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "2.5-dev"
+                },
+                "thanks": {
+                    "name": "symfony/contracts",
+                    "url": "https://github.com/symfony/contracts"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Contracts\\Service\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Generic abstractions related to writing services",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "abstractions",
+                "contracts",
+                "decoupling",
+                "interfaces",
+                "interoperability",
+                "standards"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/service-contracts/tree/v2.5.2"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-05-30T19:17:29+00:00"
+        },
+        {
+            "name": "symfony/string",
+            "version": "v5.4.12",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/string.git",
+                "reference": "2fc515e512d721bf31ea76bd02fe23ada4640058"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/string/zipball/2fc515e512d721bf31ea76bd02fe23ada4640058",
+                "reference": "2fc515e512d721bf31ea76bd02fe23ada4640058",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "symfony/polyfill-ctype": "~1.8",
+                "symfony/polyfill-intl-grapheme": "~1.0",
+                "symfony/polyfill-intl-normalizer": "~1.0",
+                "symfony/polyfill-mbstring": "~1.0",
+                "symfony/polyfill-php80": "~1.15"
+            },
+            "conflict": {
+                "symfony/translation-contracts": ">=3.0"
+            },
+            "require-dev": {
+                "symfony/error-handler": "^4.4|^5.0|^6.0",
+                "symfony/http-client": "^4.4|^5.0|^6.0",
+                "symfony/translation-contracts": "^1.1|^2",
+                "symfony/var-exporter": "^4.4|^5.0|^6.0"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "Resources/functions.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Component\\String\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "grapheme",
+                "i18n",
+                "string",
+                "unicode",
+                "utf-8",
+                "utf8"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/string/tree/v5.4.12"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-08-12T17:03:11+00:00"
+        },
+        {
+            "name": "symfony/translation-contracts",
+            "version": "v2.5.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/translation-contracts.git",
+                "reference": "136b19dd05cdf0709db6537d058bcab6dd6e2dbe"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/136b19dd05cdf0709db6537d058bcab6dd6e2dbe",
+                "reference": "136b19dd05cdf0709db6537d058bcab6dd6e2dbe",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5"
+            },
+            "suggest": {
+                "symfony/translation-implementation": ""
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "2.5-dev"
+                },
+                "thanks": {
+                    "name": "symfony/contracts",
+                    "url": "https://github.com/symfony/contracts"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Contracts\\Translation\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Generic abstractions related to translation",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "abstractions",
+                "contracts",
+                "decoupling",
+                "interfaces",
+                "interoperability",
+                "standards"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/translation-contracts/tree/v2.5.2"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-06-27T16:58:25+00:00"
+        },
+        {
+            "name": "symfony/twig-bridge",
+            "version": "v5.4.12",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/twig-bridge.git",
+                "reference": "94c3b38514c953e3e84719c96d4e578a01ca1819"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/94c3b38514c953e3e84719c96d4e578a01ca1819",
+                "reference": "94c3b38514c953e3e84719c96d4e578a01ca1819",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "symfony/polyfill-php80": "^1.16",
+                "symfony/translation-contracts": "^1.1|^2|^3",
+                "twig/twig": "^2.13|^3.0.4"
+            },
+            "conflict": {
+                "phpdocumentor/reflection-docblock": "<3.2.2",
+                "phpdocumentor/type-resolver": "<1.4.0",
+                "symfony/console": "<5.3",
+                "symfony/form": "<5.3",
+                "symfony/http-foundation": "<5.3",
+                "symfony/http-kernel": "<4.4",
+                "symfony/translation": "<5.2",
+                "symfony/workflow": "<5.2"
+            },
+            "require-dev": {
+                "doctrine/annotations": "^1.12",
+                "egulias/email-validator": "^2.1.10|^3",
+                "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
+                "symfony/asset": "^4.4|^5.0|^6.0",
+                "symfony/console": "^5.3|^6.0",
+                "symfony/dependency-injection": "^4.4|^5.0|^6.0",
+                "symfony/expression-language": "^4.4|^5.0|^6.0",
+                "symfony/finder": "^4.4|^5.0|^6.0",
+                "symfony/form": "^5.3|^6.0",
+                "symfony/http-foundation": "^5.3|^6.0",
+                "symfony/http-kernel": "^4.4|^5.0|^6.0",
+                "symfony/intl": "^4.4|^5.0|^6.0",
+                "symfony/mime": "^5.2|^6.0",
+                "symfony/polyfill-intl-icu": "~1.0",
+                "symfony/property-info": "^4.4|^5.1|^6.0",
+                "symfony/routing": "^4.4|^5.0|^6.0",
+                "symfony/security-acl": "^2.8|^3.0",
+                "symfony/security-core": "^4.4|^5.0|^6.0",
+                "symfony/security-csrf": "^4.4|^5.0|^6.0",
+                "symfony/security-http": "^4.4|^5.0|^6.0",
+                "symfony/serializer": "^5.2|^6.0",
+                "symfony/stopwatch": "^4.4|^5.0|^6.0",
+                "symfony/translation": "^5.2|^6.0",
+                "symfony/web-link": "^4.4|^5.0|^6.0",
+                "symfony/workflow": "^5.2|^6.0",
+                "symfony/yaml": "^4.4|^5.0|^6.0",
+                "twig/cssinliner-extra": "^2.12|^3",
+                "twig/inky-extra": "^2.12|^3",
+                "twig/markdown-extra": "^2.12|^3"
+            },
+            "suggest": {
+                "symfony/asset": "For using the AssetExtension",
+                "symfony/expression-language": "For using the ExpressionExtension",
+                "symfony/finder": "",
+                "symfony/form": "For using the FormExtension",
+                "symfony/http-kernel": "For using the HttpKernelExtension",
+                "symfony/routing": "For using the RoutingExtension",
+                "symfony/security-core": "For using the SecurityExtension",
+                "symfony/security-csrf": "For using the CsrfExtension",
+                "symfony/security-http": "For using the LogoutUrlExtension",
+                "symfony/stopwatch": "For using the StopwatchExtension",
+                "symfony/translation": "For using the TranslationExtension",
+                "symfony/var-dumper": "For using the DumpExtension",
+                "symfony/web-link": "For using the WebLinkExtension",
+                "symfony/yaml": "For using the YamlExtension"
+            },
+            "type": "symfony-bridge",
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Bridge\\Twig\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Provides integration for Twig with various Symfony components",
+            "homepage": "https://symfony.com",
+            "support": {
+                "source": "https://github.com/symfony/twig-bridge/tree/v5.4.12"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-08-03T13:09:21+00:00"
+        },
+        {
+            "name": "symfony/var-dumper",
+            "version": "v5.4.11",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/var-dumper.git",
+                "reference": "b8f306d7b8ef34fb3db3305be97ba8e088fb4861"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/var-dumper/zipball/b8f306d7b8ef34fb3db3305be97ba8e088fb4861",
+                "reference": "b8f306d7b8ef34fb3db3305be97ba8e088fb4861",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "symfony/polyfill-mbstring": "~1.0",
+                "symfony/polyfill-php80": "^1.16"
+            },
+            "conflict": {
+                "phpunit/phpunit": "<5.4.3",
+                "symfony/console": "<4.4"
+            },
+            "require-dev": {
+                "ext-iconv": "*",
+                "symfony/console": "^4.4|^5.0|^6.0",
+                "symfony/process": "^4.4|^5.0|^6.0",
+                "symfony/uid": "^5.1|^6.0",
+                "twig/twig": "^2.13|^3.0.4"
+            },
+            "suggest": {
+                "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).",
+                "ext-intl": "To show region name in time zone dump",
+                "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script"
+            },
+            "bin": [
+                "Resources/bin/var-dump-server"
+            ],
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "Resources/functions/dump.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Component\\VarDumper\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Provides mechanisms for walking through any arbitrary PHP variable",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "debug",
+                "dump"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/var-dumper/tree/v5.4.11"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-07-20T13:00:38+00:00"
+        },
+        {
+            "name": "symfony/var-exporter",
+            "version": "v5.4.10",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/var-exporter.git",
+                "reference": "8fc03ee75eeece3d9be1ef47d26d79bea1afb340"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/var-exporter/zipball/8fc03ee75eeece3d9be1ef47d26d79bea1afb340",
+                "reference": "8fc03ee75eeece3d9be1ef47d26d79bea1afb340",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "symfony/polyfill-php80": "^1.16"
+            },
+            "require-dev": {
+                "symfony/var-dumper": "^4.4.9|^5.0.9|^6.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\VarExporter\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Allows exporting any serializable PHP data structure to plain PHP code",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "clone",
+                "construct",
+                "export",
+                "hydrate",
+                "instantiate",
+                "serialize"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/var-exporter/tree/v5.4.10"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-05-27T12:56:18+00:00"
+        },
+        {
+            "name": "symfony/yaml",
+            "version": "v5.4.12",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/yaml.git",
+                "reference": "7a3aa21ac8ab1a96cc6de5bbcab4bc9fc943b18c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/yaml/zipball/7a3aa21ac8ab1a96cc6de5bbcab4bc9fc943b18c",
+                "reference": "7a3aa21ac8ab1a96cc6de5bbcab4bc9fc943b18c",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "symfony/deprecation-contracts": "^2.1|^3",
+                "symfony/polyfill-ctype": "^1.8"
+            },
+            "conflict": {
+                "symfony/console": "<5.3"
+            },
+            "require-dev": {
+                "symfony/console": "^5.3|^6.0"
+            },
+            "suggest": {
+                "symfony/console": "For validating YAML files using the lint command"
+            },
+            "bin": [
+                "Resources/bin/yaml-lint"
+            ],
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Yaml\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Loads and dumps YAML files",
+            "homepage": "https://symfony.com",
+            "support": {
+                "source": "https://github.com/symfony/yaml/tree/v5.4.12"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-08-02T15:52:22+00:00"
+        },
+        {
+            "name": "twig/intl-extra",
+            "version": "v3.4.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/twigphp/intl-extra.git",
+                "reference": "151e50fad9c7915bd56f0adf3f0cb3c47e6ed28a"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/twigphp/intl-extra/zipball/151e50fad9c7915bd56f0adf3f0cb3c47e6ed28a",
+                "reference": "151e50fad9c7915bd56f0adf3f0cb3c47e6ed28a",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1.3",
+                "symfony/intl": "^4.4|^5.0|^6.0",
+                "twig/twig": "^2.7|^3.0"
+            },
+            "require-dev": {
+                "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.2-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Twig\\Extra\\Intl\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com",
+                    "homepage": "http://fabien.potencier.org",
+                    "role": "Lead Developer"
+                }
+            ],
+            "description": "A Twig extension for Intl",
+            "homepage": "https://twig.symfony.com",
+            "keywords": [
+                "intl",
+                "twig"
+            ],
+            "support": {
+                "source": "https://github.com/twigphp/intl-extra/tree/v3.4.2"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/twig/twig",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-06-10T08:33:05+00:00"
+        },
+        {
+            "name": "twig/twig",
+            "version": "v3.4.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/twigphp/Twig.git",
+                "reference": "c38fd6b0b7f370c198db91ffd02e23b517426b58"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/twigphp/Twig/zipball/c38fd6b0b7f370c198db91ffd02e23b517426b58",
+                "reference": "c38fd6b0b7f370c198db91ffd02e23b517426b58",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "symfony/polyfill-ctype": "^1.8",
+                "symfony/polyfill-mbstring": "^1.3"
+            },
+            "require-dev": {
+                "psr/container": "^1.0",
+                "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.4-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Twig\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com",
+                    "homepage": "http://fabien.potencier.org",
+                    "role": "Lead Developer"
+                },
+                {
+                    "name": "Twig Team",
+                    "role": "Contributors"
+                },
+                {
+                    "name": "Armin Ronacher",
+                    "email": "armin.ronacher@active-4.com",
+                    "role": "Project Founder"
+                }
+            ],
+            "description": "Twig, the flexible, fast, and secure template language for PHP",
+            "homepage": "https://twig.symfony.com",
+            "keywords": [
+                "templating"
+            ],
+            "support": {
+                "issues": "https://github.com/twigphp/Twig/issues",
+                "source": "https://github.com/twigphp/Twig/tree/v3.4.3"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/twig/twig",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-09-28T08:42:51+00:00"
+        },
+        {
+            "name": "webmozart/assert",
+            "version": "1.11.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/webmozarts/assert.git",
+                "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991",
+                "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991",
+                "shasum": ""
+            },
+            "require": {
+                "ext-ctype": "*",
+                "php": "^7.2 || ^8.0"
+            },
+            "conflict": {
+                "phpstan/phpstan": "<0.12.20",
+                "vimeo/psalm": "<4.6.1 || 4.6.2"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^8.5.13"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.10-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Webmozart\\Assert\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Bernhard Schussek",
+                    "email": "bschussek@gmail.com"
+                }
+            ],
+            "description": "Assertions to validate method input/output with nice error messages.",
+            "keywords": [
+                "assert",
+                "check",
+                "validate"
+            ],
+            "support": {
+                "issues": "https://github.com/webmozarts/assert/issues",
+                "source": "https://github.com/webmozarts/assert/tree/1.11.0"
+            },
+            "time": "2022-06-03T18:03:27+00:00"
+        }
+    ],
+    "packages-dev": [
+        {
+            "name": "amphp/amp",
+            "version": "v2.6.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/amphp/amp.git",
+                "reference": "9d5100cebffa729aaffecd3ad25dc5aeea4f13bb"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/amphp/amp/zipball/9d5100cebffa729aaffecd3ad25dc5aeea4f13bb",
+                "reference": "9d5100cebffa729aaffecd3ad25dc5aeea4f13bb",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "require-dev": {
+                "amphp/php-cs-fixer-config": "dev-master",
+                "amphp/phpunit-util": "^1",
+                "ext-json": "*",
+                "jetbrains/phpstorm-stubs": "^2019.3",
+                "phpunit/phpunit": "^7 | ^8 | ^9",
+                "psalm/phar": "^3.11@dev",
+                "react/promise": "^2"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.x-dev"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "lib/functions.php",
+                    "lib/Internal/functions.php"
+                ],
+                "psr-4": {
+                    "Amp\\": "lib"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Daniel Lowrey",
+                    "email": "rdlowrey@php.net"
+                },
+                {
+                    "name": "Aaron Piotrowski",
+                    "email": "aaron@trowski.com"
+                },
+                {
+                    "name": "Bob Weinand",
+                    "email": "bobwei9@hotmail.com"
+                },
+                {
+                    "name": "Niklas Keller",
+                    "email": "me@kelunik.com"
+                }
+            ],
+            "description": "A non-blocking concurrency framework for PHP applications.",
+            "homepage": "https://amphp.org/amp",
+            "keywords": [
+                "async",
+                "asynchronous",
+                "awaitable",
+                "concurrency",
+                "event",
+                "event-loop",
+                "future",
+                "non-blocking",
+                "promise"
+            ],
+            "support": {
+                "irc": "irc://irc.freenode.org/amphp",
+                "issues": "https://github.com/amphp/amp/issues",
+                "source": "https://github.com/amphp/amp/tree/v2.6.2"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/amphp",
+                    "type": "github"
+                }
+            ],
+            "time": "2022-02-20T17:52:18+00:00"
+        },
+        {
+            "name": "amphp/byte-stream",
+            "version": "v1.8.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/amphp/byte-stream.git",
+                "reference": "acbd8002b3536485c997c4e019206b3f10ca15bd"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/amphp/byte-stream/zipball/acbd8002b3536485c997c4e019206b3f10ca15bd",
+                "reference": "acbd8002b3536485c997c4e019206b3f10ca15bd",
+                "shasum": ""
+            },
+            "require": {
+                "amphp/amp": "^2",
+                "php": ">=7.1"
+            },
+            "require-dev": {
+                "amphp/php-cs-fixer-config": "dev-master",
+                "amphp/phpunit-util": "^1.4",
+                "friendsofphp/php-cs-fixer": "^2.3",
+                "jetbrains/phpstorm-stubs": "^2019.3",
+                "phpunit/phpunit": "^6 || ^7 || ^8",
+                "psalm/phar": "^3.11.4"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.x-dev"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "lib/functions.php"
+                ],
+                "psr-4": {
+                    "Amp\\ByteStream\\": "lib"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Aaron Piotrowski",
+                    "email": "aaron@trowski.com"
+                },
+                {
+                    "name": "Niklas Keller",
+                    "email": "me@kelunik.com"
+                }
+            ],
+            "description": "A stream abstraction to make working with non-blocking I/O simple.",
+            "homepage": "http://amphp.org/byte-stream",
+            "keywords": [
+                "amp",
+                "amphp",
+                "async",
+                "io",
+                "non-blocking",
+                "stream"
+            ],
+            "support": {
+                "irc": "irc://irc.freenode.org/amphp",
+                "issues": "https://github.com/amphp/byte-stream/issues",
+                "source": "https://github.com/amphp/byte-stream/tree/v1.8.1"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/amphp",
+                    "type": "github"
+                }
+            ],
+            "time": "2021-03-30T17:13:30+00:00"
+        },
+        {
+            "name": "composer/package-versions-deprecated",
+            "version": "1.11.99.5",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/composer/package-versions-deprecated.git",
+                "reference": "b4f54f74ef3453349c24a845d22392cd31e65f1d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/b4f54f74ef3453349c24a845d22392cd31e65f1d",
+                "reference": "b4f54f74ef3453349c24a845d22392cd31e65f1d",
+                "shasum": ""
+            },
+            "require": {
+                "composer-plugin-api": "^1.1.0 || ^2.0",
+                "php": "^7 || ^8"
+            },
+            "replace": {
+                "ocramius/package-versions": "1.11.99"
+            },
+            "require-dev": {
+                "composer/composer": "^1.9.3 || ^2.0@dev",
+                "ext-zip": "^1.13",
+                "phpunit/phpunit": "^6.5 || ^7"
+            },
+            "type": "composer-plugin",
+            "extra": {
+                "class": "PackageVersions\\Installer",
+                "branch-alias": {
+                    "dev-master": "1.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "PackageVersions\\": "src/PackageVersions"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Marco Pivetta",
+                    "email": "ocramius@gmail.com"
+                },
+                {
+                    "name": "Jordi Boggiano",
+                    "email": "j.boggiano@seld.be"
+                }
+            ],
+            "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)",
+            "support": {
+                "issues": "https://github.com/composer/package-versions-deprecated/issues",
+                "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.5"
+            },
+            "funding": [
+                {
+                    "url": "https://packagist.com",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/composer",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-01-17T14:14:24+00:00"
+        },
+        {
+            "name": "dnoegel/php-xdg-base-dir",
+            "version": "v0.1.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/dnoegel/php-xdg-base-dir.git",
+                "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd",
+                "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.2"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~7.0|~6.0|~5.0|~4.8.35"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "XdgBaseDir\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "implementation of xdg base directory specification for php",
+            "support": {
+                "issues": "https://github.com/dnoegel/php-xdg-base-dir/issues",
+                "source": "https://github.com/dnoegel/php-xdg-base-dir/tree/v0.1.1"
+            },
+            "time": "2019-12-04T15:06:13+00:00"
+        },
+        {
+            "name": "doctrine/instantiator",
+            "version": "1.4.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/instantiator.git",
+                "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc",
+                "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.1 || ^8.0"
+            },
+            "require-dev": {
+                "doctrine/coding-standard": "^9",
+                "ext-pdo": "*",
+                "ext-phar": "*",
+                "phpbench/phpbench": "^0.16 || ^1",
+                "phpstan/phpstan": "^1.4",
+                "phpstan/phpstan-phpunit": "^1",
+                "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
+                "vimeo/psalm": "^4.22"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Marco Pivetta",
+                    "email": "ocramius@gmail.com",
+                    "homepage": "https://ocramius.github.io/"
+                }
+            ],
+            "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
+            "homepage": "https://www.doctrine-project.org/projects/instantiator.html",
+            "keywords": [
+                "constructor",
+                "instantiate"
+            ],
+            "support": {
+                "issues": "https://github.com/doctrine/instantiator/issues",
+                "source": "https://github.com/doctrine/instantiator/tree/1.4.1"
+            },
+            "funding": [
+                {
+                    "url": "https://www.doctrine-project.org/sponsorship.html",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://www.patreon.com/phpdoctrine",
+                    "type": "patreon"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-03-03T08:28:38+00:00"
+        },
+        {
+            "name": "felixfbecker/advanced-json-rpc",
+            "version": "v3.2.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/felixfbecker/php-advanced-json-rpc.git",
+                "reference": "b5f37dbff9a8ad360ca341f3240dc1c168b45447"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/b5f37dbff9a8ad360ca341f3240dc1c168b45447",
+                "reference": "b5f37dbff9a8ad360ca341f3240dc1c168b45447",
+                "shasum": ""
+            },
+            "require": {
+                "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0",
+                "php": "^7.1 || ^8.0",
+                "phpdocumentor/reflection-docblock": "^4.3.4 || ^5.0.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^7.0 || ^8.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "AdvancedJsonRpc\\": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "ISC"
+            ],
+            "authors": [
+                {
+                    "name": "Felix Becker",
+                    "email": "felix.b@outlook.com"
+                }
+            ],
+            "description": "A more advanced JSONRPC implementation",
+            "support": {
+                "issues": "https://github.com/felixfbecker/php-advanced-json-rpc/issues",
+                "source": "https://github.com/felixfbecker/php-advanced-json-rpc/tree/v3.2.1"
+            },
+            "time": "2021-06-11T22:34:44+00:00"
+        },
+        {
+            "name": "felixfbecker/language-server-protocol",
+            "version": "v1.5.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/felixfbecker/php-language-server-protocol.git",
+                "reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/6e82196ffd7c62f7794d778ca52b69feec9f2842",
+                "reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "require-dev": {
+                "phpstan/phpstan": "*",
+                "squizlabs/php_codesniffer": "^3.1",
+                "vimeo/psalm": "^4.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "LanguageServerProtocol\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "ISC"
+            ],
+            "authors": [
+                {
+                    "name": "Felix Becker",
+                    "email": "felix.b@outlook.com"
+                }
+            ],
+            "description": "PHP classes for the Language Server Protocol",
+            "keywords": [
+                "language",
+                "microsoft",
+                "php",
+                "server"
+            ],
+            "support": {
+                "issues": "https://github.com/felixfbecker/php-language-server-protocol/issues",
+                "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.5.2"
+            },
+            "time": "2022-03-02T22:36:06+00:00"
+        },
+        {
+            "name": "myclabs/deep-copy",
+            "version": "1.11.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/myclabs/DeepCopy.git",
+                "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614",
+                "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.1 || ^8.0"
+            },
+            "conflict": {
+                "doctrine/collections": "<1.6.8",
+                "doctrine/common": "<2.13.3 || >=3,<3.2.2"
+            },
+            "require-dev": {
+                "doctrine/collections": "^1.6.8",
+                "doctrine/common": "^2.13.3 || ^3.2.2",
+                "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "src/DeepCopy/deep_copy.php"
+                ],
+                "psr-4": {
+                    "DeepCopy\\": "src/DeepCopy/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "Create deep copies (clones) of your objects",
+            "keywords": [
+                "clone",
+                "copy",
+                "duplicate",
+                "object",
+                "object graph"
+            ],
+            "support": {
+                "issues": "https://github.com/myclabs/DeepCopy/issues",
+                "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0"
+            },
+            "funding": [
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-03-03T13:19:32+00:00"
+        },
+        {
+            "name": "netresearch/jsonmapper",
+            "version": "v4.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/cweiske/jsonmapper.git",
+                "reference": "8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d",
+                "reference": "8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d",
+                "shasum": ""
+            },
+            "require": {
+                "ext-json": "*",
+                "ext-pcre": "*",
+                "ext-reflection": "*",
+                "ext-spl": "*",
+                "php": ">=7.1"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0",
+                "squizlabs/php_codesniffer": "~3.5"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "JsonMapper": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "OSL-3.0"
+            ],
+            "authors": [
+                {
+                    "name": "Christian Weiske",
+                    "email": "cweiske@cweiske.de",
+                    "homepage": "http://github.com/cweiske/jsonmapper/",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Map nested JSON structures onto PHP classes",
+            "support": {
+                "email": "cweiske@cweiske.de",
+                "issues": "https://github.com/cweiske/jsonmapper/issues",
+                "source": "https://github.com/cweiske/jsonmapper/tree/v4.0.0"
+            },
+            "time": "2020-12-01T19:48:11+00:00"
+        },
+        {
+            "name": "nikic/php-parser",
+            "version": "v4.15.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/nikic/PHP-Parser.git",
+                "reference": "0ef6c55a3f47f89d7a374e6f835197a0b5fcf900"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/0ef6c55a3f47f89d7a374e6f835197a0b5fcf900",
+                "reference": "0ef6c55a3f47f89d7a374e6f835197a0b5fcf900",
+                "shasum": ""
+            },
+            "require": {
+                "ext-tokenizer": "*",
+                "php": ">=7.0"
+            },
+            "require-dev": {
+                "ircmaxell/php-yacc": "^0.0.7",
+                "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0"
+            },
+            "bin": [
+                "bin/php-parse"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "4.9-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "PhpParser\\": "lib/PhpParser"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Nikita Popov"
+                }
+            ],
+            "description": "A PHP parser written in PHP",
+            "keywords": [
+                "parser",
+                "php"
+            ],
+            "support": {
+                "issues": "https://github.com/nikic/PHP-Parser/issues",
+                "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.1"
+            },
+            "time": "2022-09-04T07:30:47+00:00"
+        },
+        {
+            "name": "openlss/lib-array2xml",
+            "version": "1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/nullivex/lib-array2xml.git",
+                "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/nullivex/lib-array2xml/zipball/a91f18a8dfc69ffabe5f9b068bc39bb202c81d90",
+                "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.2"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "LSS": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache-2.0"
+            ],
+            "authors": [
+                {
+                    "name": "Bryan Tong",
+                    "email": "bryan@nullivex.com",
+                    "homepage": "https://www.nullivex.com"
+                },
+                {
+                    "name": "Tony Butler",
+                    "email": "spudz76@gmail.com",
+                    "homepage": "https://www.nullivex.com"
+                }
+            ],
+            "description": "Array2XML conversion library credit to lalit.org",
+            "homepage": "https://www.nullivex.com",
+            "keywords": [
+                "array",
+                "array conversion",
+                "xml",
+                "xml conversion"
+            ],
+            "support": {
+                "issues": "https://github.com/nullivex/lib-array2xml/issues",
+                "source": "https://github.com/nullivex/lib-array2xml/tree/master"
+            },
+            "time": "2019-03-29T20:06:56+00:00"
+        },
+        {
+            "name": "phar-io/manifest",
+            "version": "2.0.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phar-io/manifest.git",
+                "reference": "97803eca37d319dfa7826cc2437fc020857acb53"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53",
+                "reference": "97803eca37d319dfa7826cc2437fc020857acb53",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "ext-phar": "*",
+                "ext-xmlwriter": "*",
+                "phar-io/version": "^3.0.1",
+                "php": "^7.2 || ^8.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Arne Blankerts",
+                    "email": "arne@blankerts.de",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Sebastian Heuer",
+                    "email": "sebastian@phpeople.de",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
+            "support": {
+                "issues": "https://github.com/phar-io/manifest/issues",
+                "source": "https://github.com/phar-io/manifest/tree/2.0.3"
+            },
+            "time": "2021-07-20T11:28:43+00:00"
+        },
+        {
+            "name": "phar-io/version",
+            "version": "3.2.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phar-io/version.git",
+                "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
+                "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.2 || ^8.0"
+            },
+            "type": "library",
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Arne Blankerts",
+                    "email": "arne@blankerts.de",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Sebastian Heuer",
+                    "email": "sebastian@phpeople.de",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Library for handling version information and constraints",
+            "support": {
+                "issues": "https://github.com/phar-io/version/issues",
+                "source": "https://github.com/phar-io/version/tree/3.2.1"
+            },
+            "time": "2022-02-21T01:04:05+00:00"
+        },
+        {
+            "name": "phpdocumentor/reflection-common",
+            "version": "2.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
+                "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b",
+                "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.2 || ^8.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-2.x": "2.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "phpDocumentor\\Reflection\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jaap van Otterdijk",
+                    "email": "opensource@ijaap.nl"
+                }
+            ],
+            "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
+            "homepage": "http://www.phpdoc.org",
+            "keywords": [
+                "FQSEN",
+                "phpDocumentor",
+                "phpdoc",
+                "reflection",
+                "static analysis"
+            ],
+            "support": {
+                "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues",
+                "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x"
+            },
+            "time": "2020-06-27T09:03:43+00:00"
+        },
+        {
+            "name": "phpdocumentor/reflection-docblock",
+            "version": "5.3.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
+                "reference": "622548b623e81ca6d78b721c5e029f4ce664f170"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170",
+                "reference": "622548b623e81ca6d78b721c5e029f4ce664f170",
+                "shasum": ""
+            },
+            "require": {
+                "ext-filter": "*",
+                "php": "^7.2 || ^8.0",
+                "phpdocumentor/reflection-common": "^2.2",
+                "phpdocumentor/type-resolver": "^1.3",
+                "webmozart/assert": "^1.9.1"
+            },
+            "require-dev": {
+                "mockery/mockery": "~1.3.2",
+                "psalm/phar": "^4.8"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "5.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "phpDocumentor\\Reflection\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Mike van Riel",
+                    "email": "me@mikevanriel.com"
+                },
+                {
+                    "name": "Jaap van Otterdijk",
+                    "email": "account@ijaap.nl"
+                }
+            ],
+            "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
+            "support": {
+                "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
+                "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0"
+            },
+            "time": "2021-10-19T17:43:47+00:00"
+        },
+        {
+            "name": "phpdocumentor/type-resolver",
+            "version": "1.6.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phpDocumentor/TypeResolver.git",
+                "reference": "77a32518733312af16a44300404e945338981de3"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/77a32518733312af16a44300404e945338981de3",
+                "reference": "77a32518733312af16a44300404e945338981de3",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.2 || ^8.0",
+                "phpdocumentor/reflection-common": "^2.0"
+            },
+            "require-dev": {
+                "ext-tokenizer": "*",
+                "psalm/phar": "^4.8"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-1.x": "1.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "phpDocumentor\\Reflection\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Mike van Riel",
+                    "email": "me@mikevanriel.com"
+                }
+            ],
+            "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
+            "support": {
+                "issues": "https://github.com/phpDocumentor/TypeResolver/issues",
+                "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.1"
+            },
+            "time": "2022-03-15T21:29:03+00:00"
+        },
+        {
+            "name": "phpunit/php-code-coverage",
+            "version": "9.2.17",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
+                "reference": "aa94dc41e8661fe90c7316849907cba3007b10d8"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/aa94dc41e8661fe90c7316849907cba3007b10d8",
+                "reference": "aa94dc41e8661fe90c7316849907cba3007b10d8",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "ext-libxml": "*",
+                "ext-xmlwriter": "*",
+                "nikic/php-parser": "^4.14",
+                "php": ">=7.3",
+                "phpunit/php-file-iterator": "^3.0.3",
+                "phpunit/php-text-template": "^2.0.2",
+                "sebastian/code-unit-reverse-lookup": "^2.0.2",
+                "sebastian/complexity": "^2.0",
+                "sebastian/environment": "^5.1.2",
+                "sebastian/lines-of-code": "^1.0.3",
+                "sebastian/version": "^3.0.1",
+                "theseer/tokenizer": "^1.2.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.3"
+            },
+            "suggest": {
+                "ext-pcov": "*",
+                "ext-xdebug": "*"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "9.2-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
+            "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
+            "keywords": [
+                "coverage",
+                "testing",
+                "xunit"
+            ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
+                "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.17"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2022-08-30T12:24:04+00:00"
+        },
+        {
+            "name": "phpunit/php-file-iterator",
+            "version": "3.0.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
+                "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf",
+                "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "FilterIterator implementation that filters files based on a list of suffixes.",
+            "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
+            "keywords": [
+                "filesystem",
+                "iterator"
+            ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
+                "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2021-12-02T12:48:52+00:00"
+        },
+        {
+            "name": "phpunit/php-invoker",
+            "version": "3.1.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/php-invoker.git",
+                "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67",
+                "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.3"
+            },
+            "require-dev": {
+                "ext-pcntl": "*",
+                "phpunit/phpunit": "^9.3"
+            },
+            "suggest": {
+                "ext-pcntl": "*"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.1-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Invoke callables with a timeout",
+            "homepage": "https://github.com/sebastianbergmann/php-invoker/",
+            "keywords": [
+                "process"
+            ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/php-invoker/issues",
+                "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2020-09-28T05:58:55+00:00"
+        },
+        {
+            "name": "phpunit/php-text-template",
+            "version": "2.0.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/php-text-template.git",
+                "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28",
+                "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Simple template engine.",
+            "homepage": "https://github.com/sebastianbergmann/php-text-template/",
+            "keywords": [
+                "template"
+            ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
+                "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2020-10-26T05:33:50+00:00"
+        },
+        {
+            "name": "phpunit/php-timer",
+            "version": "5.0.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/php-timer.git",
+                "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2",
+                "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "5.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Utility class for timing",
+            "homepage": "https://github.com/sebastianbergmann/php-timer/",
+            "keywords": [
+                "timer"
+            ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/php-timer/issues",
+                "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2020-10-26T13:16:10+00:00"
+        },
+        {
+            "name": "phpunit/phpunit",
+            "version": "9.5.25",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/phpunit.git",
+                "reference": "3e6f90ca7e3d02025b1d147bd8d4a89fd4ca8a1d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3e6f90ca7e3d02025b1d147bd8d4a89fd4ca8a1d",
+                "reference": "3e6f90ca7e3d02025b1d147bd8d4a89fd4ca8a1d",
+                "shasum": ""
+            },
+            "require": {
+                "doctrine/instantiator": "^1.3.1",
+                "ext-dom": "*",
+                "ext-json": "*",
+                "ext-libxml": "*",
+                "ext-mbstring": "*",
+                "ext-xml": "*",
+                "ext-xmlwriter": "*",
+                "myclabs/deep-copy": "^1.10.1",
+                "phar-io/manifest": "^2.0.3",
+                "phar-io/version": "^3.0.2",
+                "php": ">=7.3",
+                "phpunit/php-code-coverage": "^9.2.13",
+                "phpunit/php-file-iterator": "^3.0.5",
+                "phpunit/php-invoker": "^3.1.1",
+                "phpunit/php-text-template": "^2.0.3",
+                "phpunit/php-timer": "^5.0.2",
+                "sebastian/cli-parser": "^1.0.1",
+                "sebastian/code-unit": "^1.0.6",
+                "sebastian/comparator": "^4.0.8",
+                "sebastian/diff": "^4.0.3",
+                "sebastian/environment": "^5.1.3",
+                "sebastian/exporter": "^4.0.5",
+                "sebastian/global-state": "^5.0.1",
+                "sebastian/object-enumerator": "^4.0.3",
+                "sebastian/resource-operations": "^3.0.3",
+                "sebastian/type": "^3.2",
+                "sebastian/version": "^3.0.2"
+            },
+            "suggest": {
+                "ext-soap": "*",
+                "ext-xdebug": "*"
+            },
+            "bin": [
+                "phpunit"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "9.5-dev"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "src/Framework/Assert/Functions.php"
+                ],
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "The PHP Unit Testing framework.",
+            "homepage": "https://phpunit.de/",
+            "keywords": [
+                "phpunit",
+                "testing",
+                "xunit"
+            ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/phpunit/issues",
+                "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.25"
+            },
+            "funding": [
+                {
+                    "url": "https://phpunit.de/sponsors.html",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-09-25T03:44:45+00:00"
+        },
+        {
+            "name": "sebastian/cli-parser",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/cli-parser.git",
+                "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2",
+                "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Library for parsing CLI options",
+            "homepage": "https://github.com/sebastianbergmann/cli-parser",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
+                "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2020-09-28T06:08:49+00:00"
+        },
+        {
+            "name": "sebastian/code-unit",
+            "version": "1.0.8",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/code-unit.git",
+                "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120",
+                "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Collection of value objects that represent the PHP code units",
+            "homepage": "https://github.com/sebastianbergmann/code-unit",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/code-unit/issues",
+                "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2020-10-26T13:08:54+00:00"
+        },
+        {
+            "name": "sebastian/code-unit-reverse-lookup",
+            "version": "2.0.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
+                "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5",
+                "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Looks up which function or method a line of code belongs to",
+            "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
+                "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2020-09-28T05:30:19+00:00"
+        },
+        {
+            "name": "sebastian/comparator",
+            "version": "4.0.8",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/comparator.git",
+                "reference": "fa0f136dd2334583309d32b62544682ee972b51a"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a",
+                "reference": "fa0f136dd2334583309d32b62544682ee972b51a",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.3",
+                "sebastian/diff": "^4.0",
+                "sebastian/exporter": "^4.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "4.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                },
+                {
+                    "name": "Jeff Welch",
+                    "email": "whatthejeff@gmail.com"
+                },
+                {
+                    "name": "Volker Dusch",
+                    "email": "github@wallbash.com"
+                },
+                {
+                    "name": "Bernhard Schussek",
+                    "email": "bschussek@2bepublished.at"
+                }
+            ],
+            "description": "Provides the functionality to compare PHP values for equality",
+            "homepage": "https://github.com/sebastianbergmann/comparator",
+            "keywords": [
+                "comparator",
+                "compare",
+                "equality"
+            ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/comparator/issues",
+                "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2022-09-14T12:41:17+00:00"
+        },
+        {
+            "name": "sebastian/complexity",
+            "version": "2.0.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/complexity.git",
+                "reference": "739b35e53379900cc9ac327b2147867b8b6efd88"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88",
+                "reference": "739b35e53379900cc9ac327b2147867b8b6efd88",
+                "shasum": ""
+            },
+            "require": {
+                "nikic/php-parser": "^4.7",
+                "php": ">=7.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Library for calculating the complexity of PHP code units",
+            "homepage": "https://github.com/sebastianbergmann/complexity",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/complexity/issues",
+                "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2020-10-26T15:52:27+00:00"
+        },
+        {
+            "name": "sebastian/diff",
+            "version": "4.0.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/diff.git",
+                "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d",
+                "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.3",
+                "symfony/process": "^4.2 || ^5"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "4.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                },
+                {
+                    "name": "Kore Nordmann",
+                    "email": "mail@kore-nordmann.de"
+                }
+            ],
+            "description": "Diff implementation",
+            "homepage": "https://github.com/sebastianbergmann/diff",
+            "keywords": [
+                "diff",
+                "udiff",
+                "unidiff",
+                "unified diff"
+            ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/diff/issues",
+                "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2020-10-26T13:10:38+00:00"
+        },
+        {
+            "name": "sebastian/environment",
+            "version": "5.1.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/environment.git",
+                "reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/1b5dff7bb151a4db11d49d90e5408e4e938270f7",
+                "reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.3"
+            },
+            "suggest": {
+                "ext-posix": "*"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "5.1-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Provides functionality to handle HHVM/PHP environments",
+            "homepage": "http://www.github.com/sebastianbergmann/environment",
+            "keywords": [
+                "Xdebug",
+                "environment",
+                "hhvm"
+            ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/environment/issues",
+                "source": "https://github.com/sebastianbergmann/environment/tree/5.1.4"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2022-04-03T09:37:03+00:00"
+        },
+        {
+            "name": "sebastian/exporter",
+            "version": "4.0.5",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/exporter.git",
+                "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d",
+                "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.3",
+                "sebastian/recursion-context": "^4.0"
+            },
+            "require-dev": {
+                "ext-mbstring": "*",
+                "phpunit/phpunit": "^9.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "4.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                },
+                {
+                    "name": "Jeff Welch",
+                    "email": "whatthejeff@gmail.com"
+                },
+                {
+                    "name": "Volker Dusch",
+                    "email": "github@wallbash.com"
+                },
+                {
+                    "name": "Adam Harvey",
+                    "email": "aharvey@php.net"
+                },
+                {
+                    "name": "Bernhard Schussek",
+                    "email": "bschussek@gmail.com"
+                }
+            ],
+            "description": "Provides the functionality to export PHP variables for visualization",
+            "homepage": "https://www.github.com/sebastianbergmann/exporter",
+            "keywords": [
+                "export",
+                "exporter"
+            ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/exporter/issues",
+                "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2022-09-14T06:03:37+00:00"
+        },
+        {
+            "name": "sebastian/global-state",
+            "version": "5.0.5",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/global-state.git",
+                "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2",
+                "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.3",
+                "sebastian/object-reflector": "^2.0",
+                "sebastian/recursion-context": "^4.0"
+            },
+            "require-dev": {
+                "ext-dom": "*",
+                "phpunit/phpunit": "^9.3"
+            },
+            "suggest": {
+                "ext-uopz": "*"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "5.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Snapshotting of global state",
+            "homepage": "http://www.github.com/sebastianbergmann/global-state",
+            "keywords": [
+                "global state"
+            ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/global-state/issues",
+                "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2022-02-14T08:28:10+00:00"
+        },
+        {
+            "name": "sebastian/lines-of-code",
+            "version": "1.0.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/lines-of-code.git",
+                "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc",
+                "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc",
+                "shasum": ""
+            },
+            "require": {
+                "nikic/php-parser": "^4.6",
+                "php": ">=7.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Library for counting the lines of code in PHP source code",
+            "homepage": "https://github.com/sebastianbergmann/lines-of-code",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
+                "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2020-11-28T06:42:11+00:00"
+        },
+        {
+            "name": "sebastian/object-enumerator",
+            "version": "4.0.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/object-enumerator.git",
+                "reference": "5c9eeac41b290a3712d88851518825ad78f45c71"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71",
+                "reference": "5c9eeac41b290a3712d88851518825ad78f45c71",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.3",
+                "sebastian/object-reflector": "^2.0",
+                "sebastian/recursion-context": "^4.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "4.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Traverses array structures and object graphs to enumerate all referenced objects",
+            "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
+                "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2020-10-26T13:12:34+00:00"
+        },
+        {
+            "name": "sebastian/object-reflector",
+            "version": "2.0.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/object-reflector.git",
+                "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7",
+                "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Allows reflection of object attributes, including inherited and non-public ones",
+            "homepage": "https://github.com/sebastianbergmann/object-reflector/",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/object-reflector/issues",
+                "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2020-10-26T13:14:26+00:00"
+        },
+        {
+            "name": "sebastian/recursion-context",
+            "version": "4.0.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/recursion-context.git",
+                "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cd9d8cf3c5804de4341c283ed787f099f5506172",
+                "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "4.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                },
+                {
+                    "name": "Jeff Welch",
+                    "email": "whatthejeff@gmail.com"
+                },
+                {
+                    "name": "Adam Harvey",
+                    "email": "aharvey@php.net"
+                }
+            ],
+            "description": "Provides functionality to recursively process PHP variables",
+            "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
+                "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.4"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2020-10-26T13:17:30+00:00"
+        },
+        {
+            "name": "sebastian/resource-operations",
+            "version": "3.0.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/resource-operations.git",
+                "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8",
+                "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Provides a list of PHP built-in functions that operate on resources",
+            "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/resource-operations/issues",
+                "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2020-09-28T06:45:17+00:00"
+        },
+        {
+            "name": "sebastian/type",
+            "version": "3.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/type.git",
+                "reference": "fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e",
+                "reference": "fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.5"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.2-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Collection of value objects that represent the types of the PHP type system",
+            "homepage": "https://github.com/sebastianbergmann/type",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/type/issues",
+                "source": "https://github.com/sebastianbergmann/type/tree/3.2.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2022-09-12T14:47:03+00:00"
+        },
+        {
+            "name": "sebastian/version",
+            "version": "3.0.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/version.git",
+                "reference": "c6c1022351a901512170118436c764e473f6de8c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c",
+                "reference": "c6c1022351a901512170118436c764e473f6de8c",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Library that helps with managing the version number of Git-hosted PHP projects",
+            "homepage": "https://github.com/sebastianbergmann/version",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/version/issues",
+                "source": "https://github.com/sebastianbergmann/version/tree/3.0.2"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sebastianbergmann",
+                    "type": "github"
+                }
+            ],
+            "time": "2020-09-28T06:39:44+00:00"
+        },
+        {
+            "name": "simplesamlphp/simplesamlphp-test-framework",
+            "version": "v1.2.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/simplesamlphp/simplesamlphp-test-framework.git",
+                "reference": "70a601f41aebb00820b168c24f4b8177f414fc18"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/simplesamlphp/simplesamlphp-test-framework/zipball/70a601f41aebb00820b168c24f4b8177f414fc18",
+                "reference": "70a601f41aebb00820b168c24f4b8177f414fc18",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.4|^8.0",
+                "phpunit/phpunit": "^8.5|^9.5",
+                "squizlabs/php_codesniffer": "^3.6",
+                "symfony/phpunit-bridge": "^6.0",
+                "vimeo/psalm": "^4.20|^5.0.0-beta1"
+            },
+            "require-dev": {
+                "ext-curl": "*",
+                "simplesamlphp/simplesamlphp": "dev-master"
+            },
+            "bin": [
+                "bin/check-syntax-json.sh",
+                "bin/check-syntax-php.sh",
+                "bin/check-syntax-xml.sh",
+                "bin/check-syntax-yaml.sh"
+            ],
+            "type": "project",
+            "autoload": {
+                "psr-4": {
+                    "SimpleSAML\\TestUtils\\": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "LGPL-2.1-or-later"
+            ],
+            "authors": [
+                {
+                    "name": "Tim van Dijen",
+                    "email": "tvdijen@gmail.com"
+                }
+            ],
+            "description": "Test framework for SimpleSAMLphp and related repositories ",
+            "keywords": [
+                "test-framework"
+            ],
+            "support": {
+                "issues": "https://github.com/simplesamlphp/simplesamlphp-test-framework/issues",
+                "source": "https://github.com/simplesamlphp/simplesamlphp-test-framework"
+            },
+            "time": "2022-05-15T10:37:25+00:00"
+        },
+        {
+            "name": "squizlabs/php_codesniffer",
+            "version": "3.7.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
+                "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/1359e176e9307e906dc3d890bcc9603ff6d90619",
+                "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619",
+                "shasum": ""
+            },
+            "require": {
+                "ext-simplexml": "*",
+                "ext-tokenizer": "*",
+                "ext-xmlwriter": "*",
+                "php": ">=5.4.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
+            },
+            "bin": [
+                "bin/phpcs",
+                "bin/phpcbf"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.x-dev"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Greg Sherwood",
+                    "role": "lead"
+                }
+            ],
+            "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
+            "homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
+            "keywords": [
+                "phpcs",
+                "standards"
+            ],
+            "support": {
+                "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues",
+                "source": "https://github.com/squizlabs/PHP_CodeSniffer",
+                "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki"
+            },
+            "time": "2022-06-18T07:21:10+00:00"
+        },
+        {
+            "name": "symfony/phpunit-bridge",
+            "version": "v6.1.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/phpunit-bridge.git",
+                "reference": "75c2fa71d049c1f48e39d208c0cefba97e66335a"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/75c2fa71d049c1f48e39d208c0cefba97e66335a",
+                "reference": "75c2fa71d049c1f48e39d208c0cefba97e66335a",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1.3"
+            },
+            "conflict": {
+                "phpunit/phpunit": "<7.5|9.1.2"
+            },
+            "require-dev": {
+                "symfony/deprecation-contracts": "^2.1|^3.0",
+                "symfony/error-handler": "^5.4|^6.0"
+            },
+            "suggest": {
+                "symfony/error-handler": "For tracking deprecated interfaces usages at runtime with DebugClassLoader"
+            },
+            "bin": [
+                "bin/simple-phpunit"
+            ],
+            "type": "symfony-bridge",
+            "extra": {
+                "thanks": {
+                    "name": "phpunit/phpunit",
+                    "url": "https://github.com/sebastianbergmann/phpunit"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Bridge\\PhpUnit\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Provides utilities for PHPUnit, especially user deprecation notices management",
+            "homepage": "https://symfony.com",
+            "support": {
+                "source": "https://github.com/symfony/phpunit-bridge/tree/v6.1.3"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-07-28T13:40:41+00:00"
+        },
+        {
+            "name": "theseer/tokenizer",
+            "version": "1.2.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/theseer/tokenizer.git",
+                "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e",
+                "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "ext-tokenizer": "*",
+                "ext-xmlwriter": "*",
+                "php": "^7.2 || ^8.0"
+            },
+            "type": "library",
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Arne Blankerts",
+                    "email": "arne@blankerts.de",
+                    "role": "Developer"
+                }
+            ],
+            "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
+            "support": {
+                "issues": "https://github.com/theseer/tokenizer/issues",
+                "source": "https://github.com/theseer/tokenizer/tree/1.2.1"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/theseer",
+                    "type": "github"
+                }
+            ],
+            "time": "2021-07-28T10:34:58+00:00"
+        },
+        {
+            "name": "vimeo/psalm",
+            "version": "4.27.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/vimeo/psalm.git",
+                "reference": "faf106e717c37b8c81721845dba9de3d8deed8ff"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/vimeo/psalm/zipball/faf106e717c37b8c81721845dba9de3d8deed8ff",
+                "reference": "faf106e717c37b8c81721845dba9de3d8deed8ff",
+                "shasum": ""
+            },
+            "require": {
+                "amphp/amp": "^2.4.2",
+                "amphp/byte-stream": "^1.5",
+                "composer/package-versions-deprecated": "^1.8.0",
+                "composer/semver": "^1.4 || ^2.0 || ^3.0",
+                "composer/xdebug-handler": "^1.1 || ^2.0 || ^3.0",
+                "dnoegel/php-xdg-base-dir": "^0.1.1",
+                "ext-ctype": "*",
+                "ext-dom": "*",
+                "ext-json": "*",
+                "ext-libxml": "*",
+                "ext-mbstring": "*",
+                "ext-simplexml": "*",
+                "ext-tokenizer": "*",
+                "felixfbecker/advanced-json-rpc": "^3.0.3",
+                "felixfbecker/language-server-protocol": "^1.5",
+                "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0",
+                "nikic/php-parser": "^4.13",
+                "openlss/lib-array2xml": "^1.0",
+                "php": "^7.1|^8",
+                "sebastian/diff": "^3.0 || ^4.0",
+                "symfony/console": "^3.4.17 || ^4.1.6 || ^5.0 || ^6.0",
+                "symfony/polyfill-php80": "^1.25",
+                "webmozart/path-util": "^2.3"
+            },
+            "provide": {
+                "psalm/psalm": "self.version"
+            },
+            "require-dev": {
+                "bamarni/composer-bin-plugin": "^1.2",
+                "brianium/paratest": "^4.0||^6.0",
+                "ext-curl": "*",
+                "php-parallel-lint/php-parallel-lint": "^1.2",
+                "phpdocumentor/reflection-docblock": "^5",
+                "phpmyadmin/sql-parser": "5.1.0||dev-master",
+                "phpspec/prophecy": ">=1.9.0",
+                "phpunit/phpunit": "^9.0",
+                "psalm/plugin-phpunit": "^0.16",
+                "slevomat/coding-standard": "^7.0",
+                "squizlabs/php_codesniffer": "^3.5",
+                "symfony/process": "^4.3 || ^5.0 || ^6.0",
+                "weirdan/prophecy-shim": "^1.0 || ^2.0"
+            },
+            "suggest": {
+                "ext-curl": "In order to send data to shepherd",
+                "ext-igbinary": "^2.0.5 is required, used to serialize caching data"
+            },
+            "bin": [
+                "psalm",
+                "psalm-language-server",
+                "psalm-plugin",
+                "psalm-refactor",
+                "psalter"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "4.x-dev",
+                    "dev-3.x": "3.x-dev",
+                    "dev-2.x": "2.x-dev",
+                    "dev-1.x": "1.x-dev"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "src/functions.php",
+                    "src/spl_object_id.php"
+                ],
+                "psr-4": {
+                    "Psalm\\": "src/Psalm/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Matthew Brown"
+                }
+            ],
+            "description": "A static analysis tool for finding errors in PHP applications",
+            "keywords": [
+                "code",
+                "inspection",
+                "php"
+            ],
+            "support": {
+                "issues": "https://github.com/vimeo/psalm/issues",
+                "source": "https://github.com/vimeo/psalm/tree/4.27.0"
+            },
+            "time": "2022-08-31T13:47:09+00:00"
+        },
+        {
+            "name": "webmozart/path-util",
+            "version": "2.3.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/webmozart/path-util.git",
+                "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/webmozart/path-util/zipball/d939f7edc24c9a1bb9c0dee5cb05d8e859490725",
+                "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3",
+                "webmozart/assert": "~1.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.6",
+                "sebastian/version": "^1.0.1"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.3-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Webmozart\\PathUtil\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Bernhard Schussek",
+                    "email": "bschussek@gmail.com"
+                }
+            ],
+            "description": "A robust cross-platform utility for normalizing, comparing and modifying file paths.",
+            "support": {
+                "issues": "https://github.com/webmozart/path-util/issues",
+                "source": "https://github.com/webmozart/path-util/tree/2.3.0"
+            },
+            "abandoned": "symfony/filesystem",
+            "time": "2015-12-17T08:42:14+00:00"
+        }
+    ],
+    "aliases": [],
+    "minimum-stability": "stable",
+    "stability-flags": {
+        "simplesamlphp/simplesamlphp": 10
+    },
+    "prefer-stable": false,
+    "prefer-lowest": false,
+    "platform": {
+        "php": "^7.4 || ^8.0",
+        "ext-pdo": "*",
+        "ext-pdo_sqlite": "*"
+    },
+    "platform-dev": [],
+    "plugin-api-version": "2.3.0"
+}
diff --git a/config-templates/module_accounting.php b/config-templates/module_accounting.php
new file mode 100644
index 0000000..828725b
--- /dev/null
+++ b/config-templates/module_accounting.php
@@ -0,0 +1,206 @@
+<?php
+
+declare(strict_types=1);
+
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Providers;
+use SimpleSAML\Module\accounting\Stores;
+use SimpleSAML\Module\accounting\Trackers;
+
+$config = [
+    /**
+     * User ID attribute, one that is always available and that is unique to all users.
+     * If this attribute is not available, accounting will not be performed for that user.
+     *
+     * Examples:
+     * urn:oasis:names:tc:SAML:attribute:subject-id
+     * eduPersonTargetedID
+     * eduPersonPrincipalName
+     * eduPersonUniqueID
+     */
+    ModuleConfiguration::OPTION_USER_ID_ATTRIBUTE_NAME => 'urn:oasis:names:tc:SAML:attribute:subject-id',
+
+    /**
+     * Default authentication source which will be used when authenticating users in SimpleSAMLphp Profile Page.
+     */
+    ModuleConfiguration::OPTION_DEFAULT_AUTHENTICATION_SOURCE => 'default-sp',
+
+    /**
+     * Accounting processing type. There are two possible types: 'synchronous' and 'asynchronous'.
+     */
+    ModuleConfiguration::OPTION_ACCOUNTING_PROCESSING_TYPE =>
+        /**
+         * Synchronous option, meaning accounting processing will be performed during authentication itself
+         * (slower authentication).
+         */
+        ModuleConfiguration\AccountingProcessingType::VALUE_SYNCHRONOUS,
+        /**
+         * Asynchronous option, meaning for each authentication event a new job will be created for later processing
+         * (faster authentication, but requires setting up job storage and a cron entry).
+         */
+        //ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS,
+
+    /**
+     * Jobs store class. In case of the 'asynchronous' accounting processing type, this determines which class
+     * will be used to store jobs. The class must implement Stores\Interfaces\JobsStoreInterface.
+     */
+    ModuleConfiguration::OPTION_JOBS_STORE =>
+        /**
+         * Default jobs store class which expects Doctrine DBAL compatible connection to be set below.
+         */
+        Stores\Jobs\DoctrineDbal\Store::class,
+        /**
+         * PhpRedis class Redis jobs store. Expects class Redis compatible connection to be set bellow.
+         * Note: PhpRedis must be installed: https://github.com/phpredis/phpredis#installation
+         */
+        //Stores\Jobs\PhpRedis\RedisStore::class,
+
+    /**
+     * Default data tracker and provider to be used for accounting and as a source for data display in SSP UI.
+     * This class must implement Trackers\Interfaces\AuthenticationDataTrackerInterface and
+     * Providers\Interfaces\AuthenticationDataProviderInterface
+     */
+    ModuleConfiguration::OPTION_DEFAULT_DATA_TRACKER_AND_PROVIDER =>
+        /**
+         * Track each authentication event for idp / sp / user combination, and any change in idp / sp metadata or
+         * released user attributes. Each authentication event record will have data used and released at the
+         * time of the authentication event (versioned idp / sp / user data). This tracker can also be
+         * used as an authentication data provider. It expects Doctrine DBAL compatible connection
+         * to be set below. Internally it uses store class
+         * Stores\Data\DoctrineDbal\DoctrineDbal\Versioned\Store::class.
+         */
+        Trackers\Authentication\DoctrineDbal\Versioned\Tracker::class,
+
+    /**
+     * Additional trackers to run besides default data tracker. These trackers will typically only process and
+     * persist authentication data to proper data store, and won't be used to display data in SSP UI.
+     * These tracker classes must implement Trackers\Interfaces\AuthenticationDataTrackerInterface.
+     */
+    ModuleConfiguration::OPTION_ADDITIONAL_TRACKERS => [
+        // tracker-class
+    ],
+
+    /**
+     * Map of classes (stores, trackers, providers, ...) and connection keys, which defines which connections will
+     * be used. Value for connection key can be string, or it can be an array with two connection types as keys:
+     * master or slave. Master connection is single connection which will be used to write data to, and it
+     * must be set. If no slave connections are set, master will also be used to read data from. Slave
+     * connections are defined as array of strings. If slave connections are set, random one will
+     * be picked to read data from.
+     */
+    ModuleConfiguration::OPTION_CLASS_TO_CONNECTION_MAP => [
+        /**
+         * Connection key to be used by jobs store class.
+         */
+        Stores\Jobs\DoctrineDbal\Store::class => 'doctrine_dbal_pdo_mysql',
+        Stores\Jobs\PhpRedis\RedisStore::class => 'phpredis_class_redis',
+        /**
+         * Connection key to be used by this data tracker and provider.
+         */
+        Trackers\Authentication\DoctrineDbal\Versioned\Tracker::class => [
+            ModuleConfiguration\ConnectionType::MASTER => 'doctrine_dbal_pdo_mysql',
+            ModuleConfiguration\ConnectionType::SLAVE => [
+                'doctrine_dbal_pdo_mysql',
+            ],
+        ],
+    ],
+
+    /**
+     * Connections and their parameters.
+     */
+    ModuleConfiguration::OPTION_CONNECTIONS_AND_PARAMETERS => [
+        /**
+         * Examples for Doctrine DBAL compatible mysql and sqlite connection parameters are provided below (more info
+         * on https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html).
+         * There are additional parameters for: table prefix.
+         */
+        'doctrine_dbal_pdo_mysql' => [
+            'driver' => 'pdo_mysql', // (string): The built-in driver implementation to use.
+            'user' => 'user', // (string): Username to use when connecting to the database.
+            'password' => 'password', // (string): Password to use when connecting to the database.
+            'host' => 'host', // (string): Hostname of the database to connect to.
+            'port' => 3306, // (integer): Port of the database to connect to.
+            'dbname' => 'dbname', // (string): Name of the database/schema to connect to.
+            //'unix_socket' => 'unix_socet', // (string): Name of the socket used to connect to the database.
+            'charset' => 'utf8', // (string): The charset used when connecting to the database.
+            //'url' => 'mysql://user:secret@localhost/mydb?charset=utf8', // ...alternative way of providing parameters.
+            // Additional parameters not originally available in Doctrine DBAL
+            'table_prefix' => '', // (string): Prefix for each table.
+        ],
+        'doctrine_dbal_pdo_sqlite' => [
+            'driver' => 'pdo_sqlite', // (string): The built-in driver implementation to use.
+            'path' => '/path/to/db.sqlite', // (string): The filesystem path to the database file.
+            // Mutually exclusive with memory. path takes precedence.
+            'memory' => false, // (boolean): True if the SQLite database should be in-memory (non-persistent).
+            // Mutually exclusive with path. path takes precedence.
+            //'url' => 'sqlite:////path/to/db.sqlite // ...alternative way of providing path parameter.
+            //'url' => 'sqlite:///:memory:' // ...alternative way of providing memory parameter.
+            // Additional parameters not originally available in Doctrine DBAL
+            'table_prefix' => '', // (string): Prefix for each table.
+        ],
+        /**
+         * Example for PhpRedis class Redis (https://github.com/phpredis/phpredis#class-redis).
+         */
+        'phpredis_class_redis' => [
+            'host' => '127.0.0.1', // (string): can be a host, or the path to a unix domain socket.
+            'port' => 6379, // (int): default port is 6379, should be -1 for unix domain socket.
+            'connectTimeout' => 1, // (float): value in seconds (default is 0 meaning unlimited).
+            //'retryInterval' => 500, // (int): value in milliseconds (optional, default 0)
+            //'readTimeout' => 0, // (float): value in seconds (default is 0 meaning unlimited)
+            'auth' => ['phpredis', 'phpredis'], // (mixed): authentication information
+            'keyPrefix' => 'ssp_accounting:'
+        ],
+    ],
+
+    /**
+     * Job runner fine-grained configuration options.
+     *
+     * Maximum execution time for the job runner. You can use this option to limit job runner activity by combining
+     * when the job runner will run (using cron configuration) and how long the job runner will be active
+     * (execution time). This can be null, meaning it will run indefinitely, or can be set as a duration
+     * for DateInterval, examples being below. Note that when the job runner is run using Cron user
+     * interface in SimpleSAMLphp, the duration will be taken from the 'max_execution_time' ini
+     * setting, and will override this setting if ini setting is shorter.
+     * @see https://www.php.net/manual/en/dateinterval.construct.php
+     */
+    ModuleConfiguration::OPTION_JOB_RUNNER_MAXIMUM_EXECUTION_TIME => null,
+    //ModuleConfiguration::OPTION_JOB_RUNNER_MAXIMUM_EXECUTION_TIME => 'PT9M', // 9 minutes
+    //ModuleConfiguration::OPTION_JOB_RUNNER_MAXIMUM_EXECUTION_TIME => 'PT59M', // 59 minutes
+    //ModuleConfiguration::OPTION_JOB_RUNNER_MAXIMUM_EXECUTION_TIME => 'P1D', // 1 day
+
+    /**
+     * Number of processed jobs after which the job runner should take a 1-second pause.
+     *
+     * This option was introduced so that the job runner can act in a more resource friendly fashion when facing
+     * backend store. If the value is null, there will be no pause.
+     */
+    ModuleConfiguration::OPTION_JOB_RUNNER_SHOULD_PAUSE_AFTER_NUMBER_OF_JOBS_PROCESSED => 10,
+
+    /**
+     * Tracker data retention policy.
+     *
+     * Determines how long the tracked data will be stored. If null, data will be stored indefinitely. Otherwise, it
+     * can be set as a duration for DateInterval, examples being below. For this to work, a cron tag must also
+     * be configured.
+     */
+    ModuleConfiguration::OPTION_TRACKER_DATA_RETENTION_POLICY => null,
+    //ModuleConfiguration::OPTION_TRACKER_DATA_RETENTION_POLICY => 'P30D', // 30 days
+    //ModuleConfiguration::OPTION_TRACKER_DATA_RETENTION_POLICY => 'P6M', // 6 months
+    //ModuleConfiguration::OPTION_TRACKER_DATA_RETENTION_POLICY => 'P1Y', // 1 year
+
+
+    /**
+     * Cron tags.
+     *
+     * Job runner tag designates the cron tag to use when running accounting jobs. Make sure to add this tag to
+     * the cron module configuration in case of the 'asynchronous' accounting processing type.
+     */
+    ModuleConfiguration::OPTION_CRON_TAG_FOR_JOB_RUNNER => 'accounting_job_runner',
+
+    /**
+     * Tracker data retention policy tag designates the cron tag to use for enforcing data retention policy. Make sure
+     * to add this tag to the cron module configuration if data retention policy is different from null.
+     */
+    ModuleConfiguration::OPTION_CRON_TAG_FOR_TRACKER_DATA_RETENTION_POLICY =>
+        'accounting_tracker_data_retention_policy',
+];
diff --git a/hooks/hook_adminmenu.php b/hooks/hook_adminmenu.php
new file mode 100644
index 0000000..cb7b83b
--- /dev/null
+++ b/hooks/hook_adminmenu.php
@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+use SimpleSAML\Locale\Translate;
+use SimpleSAML\Module\accounting\Helpers\ModuleRoutesHelper;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+
+function accounting_hook_adminmenu(\SimpleSAML\XHTML\Template &$template): void
+{
+    $menuKey = 'menu';
+
+    $moduleRoutesHelper = new ModuleRoutesHelper();
+
+    $profilePageEntry = [
+        ModuleConfiguration::MODULE_NAME => [
+            'url' => $moduleRoutesHelper->getUrl(ModuleRoutesHelper::PATH_USER_PERSONAL_DATA),
+            'name' => Translate::noop('Profile Page'),
+        ],
+    ];
+
+    if (!isset($template->data[$menuKey]) || !is_array($template->data[$menuKey])) {
+        return;
+    }
+
+    // Use array_splice to put our entry before the "Log out" entry.
+    array_splice($template->data[$menuKey], -1, 0, $profilePageEntry);
+
+    $template->getLocalization()->addModuleDomain(ModuleConfiguration::MODULE_NAME);
+}
\ No newline at end of file
diff --git a/hooks/hook_configpage.php b/hooks/hook_configpage.php
new file mode 100644
index 0000000..a2b9513
--- /dev/null
+++ b/hooks/hook_configpage.php
@@ -0,0 +1,26 @@
+<?php
+
+declare(strict_types=1);
+
+use SimpleSAML\Locale\Translate;
+use SimpleSAML\Module\accounting\Helpers\ModuleRoutesHelper;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\XHTML\Template;
+
+function accounting_hook_configpage(Template &$template): void
+{
+    $moduleRoutesHelper = new ModuleRoutesHelper();
+
+    $dataLinksKey = 'links';
+
+    if (!isset($template->data[$dataLinksKey]) || !is_array($template->data[$dataLinksKey])) {
+        return;
+    }
+
+    $template->data[$dataLinksKey][] = [
+        'href' => $moduleRoutesHelper->getUrl(ModuleRoutesHelper::PATH_ADMIN_CONFIGURATION_STATUS),
+        'text' => Translate::noop('Accounting configuration status'),
+    ];
+
+    $template->getLocalization()->addModuleDomain(ModuleConfiguration::MODULE_NAME);
+}
diff --git a/hooks/hook_cron.php b/hooks/hook_cron.php
new file mode 100644
index 0000000..ee6c7c2
--- /dev/null
+++ b/hooks/hook_cron.php
@@ -0,0 +1,91 @@
+<?php
+
+declare(strict_types=1);
+
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Configuration;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+use SimpleSAML\Module\accounting\Services\JobRunner;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Services\Logger;
+use SimpleSAML\Module\accounting\Trackers\Builders\AuthenticationDataTrackerBuilder;
+
+function accounting_hook_cron(array &$cronInfo): void
+{
+    $moduleConfiguration = new ModuleConfiguration();
+    $logger = new Logger();
+
+    /** @var ?string $currentCronTag */
+    $currentCronTag = $cronInfo['tag'] ?? null;
+
+    if (!isset($cronInfo['summary']) || !is_array($cronInfo['summary'])) {
+        $cronInfo['summary'] = [];
+    }
+
+    /**
+     * Job runner handling.
+     */
+    $cronTagForJobRunner = $moduleConfiguration->getCronTagForJobRunner();
+    try {
+        if ($currentCronTag === $cronTagForJobRunner) {
+            $state = (new JobRunner($moduleConfiguration, Configuration::getConfig()))->run();
+            foreach ($state->getStatusMessages() as $statusMessage) {
+                $cronInfo['summary'][] = $statusMessage;
+            }
+            $message = sprintf(
+                'Job processing finished with %s successful jobs, %s failed jobs; total: %s.',
+                $state->getSuccessfulJobsProcessed(),
+                $state->getFailedJobsProcessed(),
+                $state->getTotalJobsProcessed()
+            );
+            $cronInfo['summary'][] = $message;
+        }
+    } catch (Throwable $exception) {
+        $message = 'Job runner error: ' . $exception->getMessage();
+        $cronInfo['summary'][] = $message;
+    }
+
+    if (!isset($cronInfo['summary']) || !is_array($cronInfo['summary'])) {
+        $cronInfo['summary'] = [];
+    }
+
+    /**
+     * Tracker data retention policy handling.
+     */
+    $cronTagForTrackerDataRetentionPolicy = $moduleConfiguration->getCronTagForTrackerDataRetentionPolicy();
+    try {
+        if (
+            $currentCronTag === $cronTagForTrackerDataRetentionPolicy &&
+            ($retentionPolicy = $moduleConfiguration->getTrackerDataRetentionPolicy()) !== null
+        ) {
+            $helpersManager = new HelpersManager();
+            $message = sprintf('Handling data retention policy.');
+            $logger->info($message);
+            $cronInfo['summary'][] = $message;
+            handleDataRetentionPolicy($moduleConfiguration, $logger, $helpersManager, $retentionPolicy);
+        }
+    } catch (Throwable $exception) {
+        $message = 'Error enforcing tracker data retention policy: ' . $exception->getMessage();
+        $cronInfo['summary'][] = $message;
+    }
+}
+
+function handleDataRetentionPolicy(
+    ModuleConfiguration $moduleConfiguration,
+    LoggerInterface $logger,
+    HelpersManager $helpersManager,
+    DateInterval $retentionPolicy
+): void {
+    // Handle default data tracker and provider
+    (new AuthenticationDataTrackerBuilder($moduleConfiguration, $logger, $helpersManager))
+        ->build($moduleConfiguration->getDefaultDataTrackerAndProviderClass())
+        ->enforceDataRetentionPolicy($retentionPolicy);
+
+    $additionalTrackers = $moduleConfiguration->getAdditionalTrackers();
+
+    foreach ($additionalTrackers as $tracker) {
+        (new AuthenticationDataTrackerBuilder($moduleConfiguration, $logger, $helpersManager))
+            ->build($tracker)
+            ->enforceDataRetentionPolicy($retentionPolicy);
+    }
+}
\ No newline at end of file
diff --git a/locales/en/LC_MESSAGES/accounting.po b/locales/en/LC_MESSAGES/accounting.po
new file mode 100644
index 0000000..371de5e
--- /dev/null
+++ b/locales/en/LC_MESSAGES/accounting.po
@@ -0,0 +1,18 @@
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: SimpleSAMLphp 2.0.0\n"
+"Report-Msgid-Bugs-To: simplesamlphp-translation@googlegroups.com\n"
+"POT-Creation-Date: 2016-10-12 09:31+0200\n"
+"PO-Revision-Date: 2022-01-09 12:14+0200\n"
+"Last-Translator: Marko Ivancic <mivanci@srce.hr\n"
+"Language: en\n"
+"Language-Team: \n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 2.3.4\n"
+
+msgid "Accounting"
+msgstr "Accounting"
diff --git a/phpcs.xml b/phpcs.xml
new file mode 100644
index 0000000..2ea895d
--- /dev/null
+++ b/phpcs.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<ruleset name="SimpleSAMLphp accounting module ruleset">
+
+    <file>config-templates</file>
+    <file>src</file>
+    <file>tests</file>
+    <file>www</file>
+
+    <!-- Use this to exclude paths. You can have multiple patterns -->
+    <!--<exclude-pattern>*/tests/*</exclude-pattern>-->
+    <!--<exclude-pattern>*/other/*</exclude-pattern>-->
+    <exclude-pattern>www/assets/*</exclude-pattern>
+
+    <!-- This is the rule we inherit from. If you want to exlude some specific rules, see the docs on how to do that -->
+    <rule ref="PSR12"/>
+</ruleset>
+
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 0000000..cd24325
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd"
+         bootstrap="vendor/autoload.php"
+         cacheResultFile="build/.phpunit.cache/test-results"
+         executionOrder="depends,defects"
+         forceCoversAnnotation="true"
+         beStrictAboutCoversAnnotation="true"
+         beStrictAboutOutputDuringTests="true"
+         beStrictAboutTodoAnnotatedTests="true"
+         convertDeprecationsToExceptions="true"
+         failOnRisky="true"
+         failOnWarning="true"
+         verbose="true">
+
+    <testsuites>
+        <testsuite name="default">
+            <directory>tests</directory>
+        </testsuite>
+    </testsuites>
+
+    <coverage cacheDirectory="build/.phpunit.cache/code-coverage"
+              processUncoveredFiles="true">
+        <include>
+            <directory suffix=".php">src</directory>
+        </include>
+
+        <report>
+            <clover outputFile="build/coverage/clover.xml"/>
+            <html outputDirectory="build/coverage/html"/>
+            <text outputFile="php://stdout"/>
+        </report>
+    </coverage>
+
+    <logging>
+        <junit outputFile="build/logs/junit.xml"/>
+    </logging>
+
+    <php>
+        <env name="SIMPLESAMLPHP_CONFIG_DIR" value="tests/config-templates"/>
+    </php>
+</phpunit>
diff --git a/psalm.xml b/psalm.xml
new file mode 100644
index 0000000..ccad21a
--- /dev/null
+++ b/psalm.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+<psalm
+    errorLevel="1"
+    resolveFromConfigFile="true"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns="https://getpsalm.org/schema/config"
+    xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
+>
+    <projectFiles>
+        <directory name="src" />
+        <directory name="config-templates" />
+        <directory name="tests" />
+        <directory name="www" />
+        <directory name="hooks" />
+
+        <ignoreFiles>
+            <directory name="vendor" />
+        </ignoreFiles>
+    </projectFiles>
+
+    <issueHandlers>
+        <!-- Ignore the fact that $config variable is not used in particular config files. -->
+        <UnusedVariable>
+            <errorLevel type="suppress">
+                <directory name="config-templates" />
+                <directory name="tests/config-templates" />
+                <directory name="tests/attributemap" />
+            </errorLevel>
+        </UnusedVariable>
+
+        <!--
+        Ignore PropertyNotSetInConstructor for phpunit tests. For example, this will ignore things like
+        "Property SomeTestClass::$backupStaticAttributes is not defined in constructor of SomeTestClass..."
+        -->
+        <PropertyNotSetInConstructor>
+            <errorLevel type="suppress">
+                <directory name="tests" />
+            </errorLevel>
+        </PropertyNotSetInConstructor>
+    </issueHandlers>
+</psalm>
diff --git a/routing/routes/routes.yml b/routing/routes/routes.yml
new file mode 100644
index 0000000..79241fb
--- /dev/null
+++ b/routing/routes/routes.yml
@@ -0,0 +1,28 @@
+
+# TODO mivanci delete test route
+accounting-test:
+    path:       /test
+    defaults:   { _controller: 'SimpleSAML\Module\accounting\Http\Controllers\Test::test' }
+
+accounting-admin-configuration-status:
+    path:       /admin/configuration/status
+    defaults:   { _controller: 'SimpleSAML\Module\accounting\Http\Controllers\Admin\Configuration::status' }
+
+accounting-user-personal-data:
+    path: /user/personal-data
+    defaults:   { _controller: 'SimpleSAML\Module\accounting\Http\Controllers\User\Profile::personalData' }
+
+accounting-user-connected-organizations:
+    path: /user/connected-organizations
+    defaults:   { _controller: 'SimpleSAML\Module\accounting\Http\Controllers\User\Profile::connectedOrganizations' }
+
+accounting-user-activity:
+    path: /user/activity
+    defaults:   { _controller: 'SimpleSAML\Module\accounting\Http\Controllers\User\Profile::activity' }
+
+accounting-user-logout:
+    path: /user/logout
+    methods:
+        - GET
+        - POST
+    defaults:   { _controller: 'SimpleSAML\Module\accounting\Http\Controllers\User\Profile::logout' }
diff --git a/routing/services/services.yml b/routing/services/services.yml
new file mode 100644
index 0000000..a85987f
--- /dev/null
+++ b/routing/services/services.yml
@@ -0,0 +1,19 @@
+services:
+  # default configuration for services in *this* file
+  _defaults:
+    autowire: true
+    public: false
+    bind:
+      Psr\Log\LoggerInterface: '@accounting.logger'
+
+  # Services
+  SimpleSAML\Module\accounting\:
+    resource: '../../src/*'
+    exclude: '../../src/{Http/Controllers}'
+  # Service aliases
+  accounting.logger:
+    class: SimpleSAML\Module\accounting\Services\Logger
+  # Controllers
+  SimpleSAML\Module\accounting\Http\Controllers\:
+    resource: '../../src/Http/Controllers/*'
+    tags: ['controller.service_arguments']
\ No newline at end of file
diff --git a/src/Auth/Process/Accounting.php b/src/Auth/Process/Accounting.php
new file mode 100644
index 0000000..817fa9e
--- /dev/null
+++ b/src/Auth/Process/Accounting.php
@@ -0,0 +1,98 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Auth\Process;
+
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Auth\ProcessingFilter;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event;
+use SimpleSAML\Module\accounting\Entities\Authentication\State;
+use SimpleSAML\Module\accounting\Exceptions\StoreException;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+use SimpleSAML\Module\accounting\Services\Logger;
+use SimpleSAML\Module\accounting\Stores\Builders\JobsStoreBuilder;
+use SimpleSAML\Module\accounting\Trackers\Builders\AuthenticationDataTrackerBuilder;
+
+class Accounting extends ProcessingFilter
+{
+    protected ModuleConfiguration $moduleConfiguration;
+    protected JobsStoreBuilder $jobsStoreBuilder;
+    protected LoggerInterface $logger;
+    protected AuthenticationDataTrackerBuilder $authenticationDataTrackerBuilder;
+    protected HelpersManager $helpersManager;
+
+    /**
+     * @param array $config
+     * @param mixed $reserved
+     * @param ModuleConfiguration|null $moduleConfiguration
+     * @param LoggerInterface|null $logger
+     * @param HelpersManager|null $helpersManager
+     * @param JobsStoreBuilder|null $jobsStoreBuilder
+     * @param AuthenticationDataTrackerBuilder|null $authenticationDataTrackerBuilder
+     */
+    public function __construct(
+        array &$config,
+        $reserved,
+        ModuleConfiguration $moduleConfiguration = null,
+        LoggerInterface $logger = null,
+        HelpersManager $helpersManager = null,
+        JobsStoreBuilder $jobsStoreBuilder = null,
+        AuthenticationDataTrackerBuilder $authenticationDataTrackerBuilder = null
+    ) {
+        parent::__construct($config, $reserved);
+
+        $this->moduleConfiguration = $moduleConfiguration ?? new ModuleConfiguration();
+        $this->logger = $logger ?? new Logger();
+        $this->helpersManager = $helpersManager ?? new HelpersManager();
+        $this->jobsStoreBuilder = $jobsStoreBuilder ??
+            new JobsStoreBuilder($this->moduleConfiguration, $this->logger, $this->helpersManager);
+
+        $this->authenticationDataTrackerBuilder = $authenticationDataTrackerBuilder ??
+            new AuthenticationDataTrackerBuilder($this->moduleConfiguration, $this->logger, $this->helpersManager);
+    }
+
+    /**
+     */
+    public function process(array &$state): void
+    {
+        try {
+            $authenticationEvent = new Event(new State($state));
+
+            if ($this->isAccountingProcessingTypeAsynchronous()) {
+                // Only create authentication event job for later processing...
+                $this->createAuthenticationEventJob($authenticationEvent);
+                return;
+            }
+
+            // Accounting type is synchronous, so do the processing right away...
+            $configuredTrackers = array_merge(
+                [$this->moduleConfiguration->getDefaultDataTrackerAndProviderClass()],
+                $this->moduleConfiguration->getAdditionalTrackers()
+            );
+
+            foreach ($configuredTrackers as $tracker) {
+                ($this->authenticationDataTrackerBuilder->build($tracker))->process($authenticationEvent);
+            }
+        } catch (\Throwable $exception) {
+            $message = sprintf('Accounting error, skipping... Error was: %s.', $exception->getMessage());
+            $this->logger->error($message, $state);
+        }
+    }
+
+    protected function isAccountingProcessingTypeAsynchronous(): bool
+    {
+        return $this->moduleConfiguration->getAccountingProcessingType() ===
+            ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS;
+    }
+
+    /**
+     * @throws StoreException
+     */
+    protected function createAuthenticationEventJob(Event $authenticationEvent): void
+    {
+        ($this->jobsStoreBuilder->build($this->moduleConfiguration->getJobsStoreClass()))
+            ->enqueue(new Event\Job($authenticationEvent));
+    }
+}
diff --git a/src/Entities/Activity.php b/src/Entities/Activity.php
new file mode 100644
index 0000000..7371efd
--- /dev/null
+++ b/src/Entities/Activity.php
@@ -0,0 +1,59 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Entities;
+
+use DateTimeImmutable;
+
+class Activity
+{
+    protected ServiceProvider $serviceProvider;
+    protected User $user;
+    protected DateTimeImmutable $happenedAt;
+    protected ?string $clientIpAddress;
+
+    public function __construct(
+        ServiceProvider $serviceProvider,
+        User $user,
+        DateTimeImmutable $happenedAt,
+        ?string $clientIpAddress
+    ) {
+        $this->serviceProvider = $serviceProvider;
+        $this->user = $user;
+        $this->happenedAt = $happenedAt;
+        $this->clientIpAddress = $clientIpAddress;
+    }
+
+    /**
+     * @return ServiceProvider
+     */
+    public function getServiceProvider(): ServiceProvider
+    {
+        return $this->serviceProvider;
+    }
+
+    /**
+     * @return User
+     */
+    public function getUser(): User
+    {
+        return $this->user;
+    }
+
+    /**
+     * @return DateTimeImmutable
+     */
+    public function getHappenedAt(): DateTimeImmutable
+    {
+        return $this->happenedAt;
+    }
+
+    /**
+     * @return string|null
+     */
+    public function getClientIpAddress(): ?string
+    {
+        return $this->clientIpAddress;
+    }
+}
diff --git a/src/Entities/Activity/Bag.php b/src/Entities/Activity/Bag.php
new file mode 100644
index 0000000..7e91a1c
--- /dev/null
+++ b/src/Entities/Activity/Bag.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace SimpleSAML\Module\accounting\Entities\Activity;
+
+use SimpleSAML\Module\accounting\Entities\Activity;
+
+class Bag
+{
+    protected array $activities = [];
+
+    public function add(Activity $activity): void
+    {
+        $this->activities[] = $activity;
+    }
+
+    public function getAll(): array
+    {
+        return $this->activities;
+    }
+}
diff --git a/src/Entities/Authentication/Event.php b/src/Entities/Authentication/Event.php
new file mode 100644
index 0000000..08c9e8c
--- /dev/null
+++ b/src/Entities/Authentication/Event.php
@@ -0,0 +1,29 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Entities\Authentication;
+
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload;
+
+class Event extends AbstractPayload
+{
+    protected State $state;
+    protected \DateTimeImmutable $happenedAt;
+
+    public function __construct(State $state, \DateTimeImmutable $happenedAt = null)
+    {
+        $this->state = $state;
+        $this->happenedAt = $happenedAt ?? new \DateTimeImmutable();
+    }
+
+    public function getState(): State
+    {
+        return $this->state;
+    }
+
+    public function getHappenedAt(): \DateTimeImmutable
+    {
+        return $this->happenedAt;
+    }
+}
diff --git a/src/Entities/Authentication/Event/Job.php b/src/Entities/Authentication/Event/Job.php
new file mode 100644
index 0000000..5cea7d9
--- /dev/null
+++ b/src/Entities/Authentication/Event/Job.php
@@ -0,0 +1,37 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Entities\Authentication\Event;
+
+use SimpleSAML\Module\accounting\Entities\Authentication\Event;
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractJob;
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload;
+use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+
+class Job extends AbstractJob
+{
+    public function getPayload(): Event
+    {
+        return $this->validatePayload($this->payload);
+    }
+
+    public function setPayload(AbstractPayload $payload): void
+    {
+        $this->payload = $this->validatePayload($payload);
+    }
+
+    protected function validatePayload(AbstractPayload $payload): Event
+    {
+        if (! ($payload instanceof Event)) {
+            throw new UnexpectedValueException('Event Job payload must be of type Event.');
+        }
+
+        return $payload;
+    }
+
+    public function getType(): string
+    {
+        return self::class;
+    }
+}
diff --git a/src/Entities/Authentication/State.php b/src/Entities/Authentication/State.php
new file mode 100644
index 0000000..899b3e7
--- /dev/null
+++ b/src/Entities/Authentication/State.php
@@ -0,0 +1,198 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Entities\Authentication;
+
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider;
+use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+use SimpleSAML\Module\accounting\Helpers\NetworkHelper;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+
+class State
+{
+    public const KEY_ATTRIBUTES = 'Attributes';
+    public const KEY_AUTHENTICATION_INSTANT = 'AuthnInstant';
+    public const KEY_IDENTITY_PROVIDER_METADATA = 'IdPMetadata';
+    public const KEY_SOURCE = 'Source';
+    public const KEY_SERVICE_PROVIDER_METADATA = 'SPMetadata';
+    public const KEY_DESTINATION = 'Destination';
+
+    public const KEY_ACCOUNTING = 'accounting';
+    public const ACCOUNTING_KEY_CLIENT_IP_ADDRESS = 'client_ip_address';
+
+    protected string $identityProviderEntityId;
+    protected string $serviceProviderEntityId;
+    protected array $attributes;
+    protected \DateTimeImmutable $createdAt;
+    protected ?\DateTimeImmutable $authenticationInstant;
+    protected array $identityProviderMetadata;
+    protected array $serviceProviderMetadata;
+    protected ?string $clientIpAddress;
+    protected HelpersManager $helpersManager;
+
+    public function __construct(
+        array $state,
+        \DateTimeImmutable $createdAt = null,
+        HelpersManager $helpersManager = null
+    ) {
+        $this->createdAt = $createdAt ?? new \DateTimeImmutable();
+        $this->helpersManager = $helpersManager ?? new HelpersManager();
+
+        $this->identityProviderMetadata = $this->resolveIdentityProviderMetadata($state);
+        $this->identityProviderEntityId = $this->resolveIdentityProviderEntityId();
+        $this->serviceProviderMetadata = $this->resolveServiceProviderMetadata($state);
+        $this->serviceProviderEntityId = $this->resolveServiceProviderEntityId();
+        $this->attributes = $this->resolveAttributes($state);
+        $this->authenticationInstant = $this->resolveAuthenticationInstant($state);
+        $this->clientIpAddress = $this->resolveClientIpAddress($state);
+    }
+
+    protected function resolveIdentityProviderEntityId(): string
+    {
+        if (
+            !empty($this->identityProviderMetadata[AbstractProvider::METADATA_KEY_ENTITY_ID]) &&
+            is_string($this->identityProviderMetadata[AbstractProvider::METADATA_KEY_ENTITY_ID])
+        ) {
+            return $this->identityProviderMetadata[AbstractProvider::METADATA_KEY_ENTITY_ID];
+        }
+
+        throw new UnexpectedValueException('IdP metadata array does not contain entity ID.');
+    }
+
+    protected function resolveServiceProviderEntityId(): string
+    {
+        if (
+            !empty($this->serviceProviderMetadata[AbstractProvider::METADATA_KEY_ENTITY_ID]) &&
+            is_string($this->serviceProviderMetadata[AbstractProvider::METADATA_KEY_ENTITY_ID])
+        ) {
+            return $this->serviceProviderMetadata[AbstractProvider::METADATA_KEY_ENTITY_ID];
+        }
+
+        throw new UnexpectedValueException('SP metadata array does not contain entity ID.');
+    }
+
+    protected function resolveAttributes(array $state): array
+    {
+        if (empty($state[self::KEY_ATTRIBUTES]) || !is_array($state[self::KEY_ATTRIBUTES])) {
+            throw new UnexpectedValueException('State array does not contain user attributes.');
+        }
+
+        return $state[self::KEY_ATTRIBUTES];
+    }
+
+    public function getIdentityProviderEntityId(): string
+    {
+        return $this->identityProviderEntityId;
+    }
+
+    public function getServiceProviderEntityId(): string
+    {
+        return $this->serviceProviderEntityId;
+    }
+
+    public function getAttributes(): array
+    {
+        return $this->attributes;
+    }
+
+    public function getAttributeValue(string $attributeName): ?string
+    {
+        if (!empty($this->attributes[$attributeName]) && is_array($this->attributes[$attributeName])) {
+            return (string)reset($this->attributes[$attributeName]);
+        }
+
+        return null;
+    }
+
+    public function getCreatedAt(): \DateTimeImmutable
+    {
+        return $this->createdAt;
+    }
+
+    protected function resolveAuthenticationInstant(array $state): ?\DateTimeImmutable
+    {
+        if (empty($state[self::KEY_AUTHENTICATION_INSTANT])) {
+            return null;
+        }
+
+        $authInstant = (string)$state[self::KEY_AUTHENTICATION_INSTANT];
+
+        try {
+            return new \DateTimeImmutable('@' . $authInstant);
+        } catch (\Throwable $exception) {
+            $message = sprintf(
+                'Unable to create DateTimeImmutable using AuthInstant value \'%s\'. Error was: %s.',
+                $authInstant,
+                $exception->getMessage()
+            );
+            throw new UnexpectedValueException($message);
+        }
+    }
+
+    public function getAuthenticationInstant(): ?\DateTimeImmutable
+    {
+        return $this->authenticationInstant;
+    }
+
+    protected function resolveIdentityProviderMetadata(array $state): array
+    {
+        if (
+            !empty($state[self::KEY_IDENTITY_PROVIDER_METADATA]) &&
+            is_array($state[self::KEY_IDENTITY_PROVIDER_METADATA])
+        ) {
+            return $state[self::KEY_IDENTITY_PROVIDER_METADATA];
+        } elseif (!empty($state[self::KEY_SOURCE]) && is_array($state[self::KEY_SOURCE])) {
+            return $state[self::KEY_SOURCE];
+        }
+
+        throw new UnexpectedValueException('State array does not contain IdP metadata.');
+    }
+
+    protected function resolveServiceProviderMetadata(array $state): array
+    {
+        if (
+            !empty($state[self::KEY_SERVICE_PROVIDER_METADATA]) &&
+            is_array($state[self::KEY_SERVICE_PROVIDER_METADATA])
+        ) {
+            return $state[self::KEY_SERVICE_PROVIDER_METADATA];
+        } elseif (!empty($state[self::KEY_DESTINATION]) && is_array($state[self::KEY_DESTINATION])) {
+            return $state[self::KEY_DESTINATION];
+        }
+
+        throw new UnexpectedValueException('State array does not contain SP metadata.');
+    }
+
+    /**
+     * @return array
+     */
+    public function getIdentityProviderMetadata(): array
+    {
+        return $this->identityProviderMetadata;
+    }
+
+    /**
+     * @return array
+     */
+    public function getServiceProviderMetadata(): array
+    {
+        return $this->serviceProviderMetadata;
+    }
+
+    protected function resolveClientIpAddress(array $state): ?string
+    {
+        return $this->helpersManager->getNetworkHelper()->resolveClientIpAddress(
+            isset($state[self::KEY_ACCOUNTING][self::ACCOUNTING_KEY_CLIENT_IP_ADDRESS]) ?
+                (string)$state[self::KEY_ACCOUNTING][self::ACCOUNTING_KEY_CLIENT_IP_ADDRESS]
+                : null
+        );
+    }
+
+    /**
+     * @return string|null
+     */
+    public function getClientIpAddress(): ?string
+    {
+        return $this->clientIpAddress;
+    }
+}
diff --git a/src/Entities/Bases/AbstractJob.php b/src/Entities/Bases/AbstractJob.php
new file mode 100644
index 0000000..4b9380e
--- /dev/null
+++ b/src/Entities/Bases/AbstractJob.php
@@ -0,0 +1,47 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Entities\Bases;
+
+use DateTimeImmutable;
+use SimpleSAML\Module\accounting\Entities\Interfaces\JobInterface;
+
+abstract class AbstractJob implements JobInterface
+{
+    protected AbstractPayload $payload;
+    protected ?int $id;
+    protected DateTimeImmutable $createdAt;
+
+    public function __construct(
+        AbstractPayload $payload,
+        int $id = null,
+        DateTimeImmutable $createdAt = null
+    ) {
+        $this->setPayload($payload);
+        $this->id = $id;
+        $this->createdAt = $createdAt ?? new DateTimeImmutable();
+    }
+
+    public function getId(): ?int
+    {
+        return $this->id;
+    }
+
+    public function getPayload(): AbstractPayload
+    {
+        return $this->payload;
+    }
+
+    public function setPayload(AbstractPayload $payload): void
+    {
+        $this->payload = $payload;
+    }
+
+    public function getCreatedAt(): DateTimeImmutable
+    {
+        return $this->createdAt;
+    }
+
+    abstract public function getType(): string;
+}
diff --git a/src/Entities/Bases/AbstractPayload.php b/src/Entities/Bases/AbstractPayload.php
new file mode 100644
index 0000000..f01d96b
--- /dev/null
+++ b/src/Entities/Bases/AbstractPayload.php
@@ -0,0 +1,9 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Entities\Bases;
+
+abstract class AbstractPayload
+{
+}
diff --git a/src/Entities/Bases/AbstractProvider.php b/src/Entities/Bases/AbstractProvider.php
new file mode 100644
index 0000000..56c0927
--- /dev/null
+++ b/src/Entities/Bases/AbstractProvider.php
@@ -0,0 +1,76 @@
+<?php
+
+namespace SimpleSAML\Module\accounting\Entities\Bases;
+
+use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+
+abstract class AbstractProvider
+{
+    public const METADATA_KEY_NAME = 'name';
+    public const METADATA_KEY_ENTITY_ID = 'entityid';
+    public const METADATA_KEY_DESCRIPTION = 'description';
+
+    protected array $metadata;
+    protected string $entityId;
+
+    public function __construct(array $metadata)
+    {
+        $this->metadata = $metadata;
+        $this->entityId = $this->resolveEntityId();
+    }
+
+    public function getMetadata(): array
+    {
+        return $this->metadata;
+    }
+
+    public function getName(string $locale = 'en'): ?string
+    {
+        return $this->resolveOptionallyLocalizedString(self::METADATA_KEY_NAME, $locale);
+    }
+
+    public function getEntityId(): string
+    {
+        return $this->entityId;
+    }
+
+    public function getDescription(string $locale = 'en'): ?string
+    {
+        return $this->resolveOptionallyLocalizedString(self::METADATA_KEY_DESCRIPTION, $locale);
+    }
+
+
+    protected function resolveEntityId(): string
+    {
+        if (
+            !empty($this->metadata[self::METADATA_KEY_ENTITY_ID]) &&
+            is_string($this->metadata[self::METADATA_KEY_ENTITY_ID])
+        ) {
+            return $this->metadata[self::METADATA_KEY_ENTITY_ID];
+        }
+
+        throw new UnexpectedValueException('Provider entity metadata does not contain entity ID.');
+    }
+
+    protected function resolveOptionallyLocalizedString(string $key, string $locale = 'en'): ?string
+    {
+        if (!isset($this->metadata[$key])) {
+            return null;
+        }
+
+        // Check for non-localized version.
+        if (is_string($this->metadata[$key])) {
+            return $this->metadata[$key];
+        }
+
+        if (
+            is_array($this->metadata[$key]) &&
+            !empty($this->metadata[$key][$locale]) &&
+            is_string($this->metadata[$key][$locale])
+        ) {
+            return $this->metadata[$key][$locale];
+        }
+
+        return null;
+    }
+}
diff --git a/src/Entities/ConnectedServiceProvider.php b/src/Entities/ConnectedServiceProvider.php
new file mode 100644
index 0000000..21bf0fc
--- /dev/null
+++ b/src/Entities/ConnectedServiceProvider.php
@@ -0,0 +1,79 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Entities;
+
+/**
+ * Represents a Service Provider to which a user has authenticated at least once.
+ */
+class ConnectedServiceProvider
+{
+    protected ServiceProvider $serviceProvider;
+    protected int $numberOfAuthentications;
+    protected \DateTimeImmutable $lastAuthenticationAt;
+    protected \DateTimeImmutable $firstAuthenticationAt;
+    protected User $user;
+
+    /**
+     * TODO mivanci make sortable by name (or entity ID if not present), number of authns, last/first authn.
+     * @param ServiceProvider $serviceProvider
+     * @param int $numberOfAuthentications
+     * @param \DateTimeImmutable $lastAuthenticationAt
+     * @param \DateTimeImmutable $firstAuthenticationAt
+     * @param User $user
+     */
+    public function __construct(
+        ServiceProvider $serviceProvider,
+        int $numberOfAuthentications,
+        \DateTimeImmutable $lastAuthenticationAt,
+        \DateTimeImmutable $firstAuthenticationAt,
+        User $user
+    ) {
+        $this->serviceProvider = $serviceProvider;
+        $this->numberOfAuthentications = $numberOfAuthentications;
+        $this->lastAuthenticationAt = $lastAuthenticationAt;
+        $this->firstAuthenticationAt = $firstAuthenticationAt;
+        $this->user = $user;
+    }
+
+    /**
+     * @return ServiceProvider
+     */
+    public function getServiceProvider(): ServiceProvider
+    {
+        return $this->serviceProvider;
+    }
+
+    /**
+     * @return int
+     */
+    public function getNumberOfAuthentications(): int
+    {
+        return $this->numberOfAuthentications;
+    }
+
+    /**
+     * @return \DateTimeImmutable
+     */
+    public function getLastAuthenticationAt(): \DateTimeImmutable
+    {
+        return $this->lastAuthenticationAt;
+    }
+
+    /**
+     * @return \DateTimeImmutable
+     */
+    public function getFirstAuthenticationAt(): \DateTimeImmutable
+    {
+        return $this->firstAuthenticationAt;
+    }
+
+    /**
+     * @return User
+     */
+    public function getUser(): User
+    {
+        return $this->user;
+    }
+}
diff --git a/src/Entities/ConnectedServiceProvider/Bag.php b/src/Entities/ConnectedServiceProvider/Bag.php
new file mode 100644
index 0000000..9507d8f
--- /dev/null
+++ b/src/Entities/ConnectedServiceProvider/Bag.php
@@ -0,0 +1,27 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider;
+
+use SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider;
+
+class Bag
+{
+    /**
+     * @var ConnectedServiceProvider[]
+     */
+    protected array $connectedServiceProviders = [];
+
+    public function addOrReplace(ConnectedServiceProvider $connectedServiceProvider): void
+    {
+        $spEntityId = $connectedServiceProvider->getServiceProvider()->getEntityId();
+
+        $this->connectedServiceProviders[$spEntityId] = $connectedServiceProvider;
+    }
+
+    public function getAll(): array
+    {
+        return $this->connectedServiceProviders;
+    }
+}
diff --git a/src/Entities/GenericJob.php b/src/Entities/GenericJob.php
new file mode 100644
index 0000000..5031ba4
--- /dev/null
+++ b/src/Entities/GenericJob.php
@@ -0,0 +1,13 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Entities;
+
+class GenericJob extends Bases\AbstractJob
+{
+    public function getType(): string
+    {
+        return self::class;
+    }
+}
diff --git a/src/Entities/IdentityProvider.php b/src/Entities/IdentityProvider.php
new file mode 100644
index 0000000..3207e91
--- /dev/null
+++ b/src/Entities/IdentityProvider.php
@@ -0,0 +1,11 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Entities;
+
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider;
+
+class IdentityProvider extends AbstractProvider
+{
+}
diff --git a/src/Entities/Interfaces/JobInterface.php b/src/Entities/Interfaces/JobInterface.php
new file mode 100644
index 0000000..9578ea9
--- /dev/null
+++ b/src/Entities/Interfaces/JobInterface.php
@@ -0,0 +1,21 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Entities\Interfaces;
+
+use DateTimeImmutable;
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload;
+
+interface JobInterface
+{
+    public function getId(): ?int;
+
+    public function getPayload(): AbstractPayload;
+
+    public function setPayload(AbstractPayload $payload): void;
+
+    public function getType(): string;
+
+    public function getCreatedAt(): DateTimeImmutable;
+}
diff --git a/src/Entities/ServiceProvider.php b/src/Entities/ServiceProvider.php
new file mode 100644
index 0000000..c5696c8
--- /dev/null
+++ b/src/Entities/ServiceProvider.php
@@ -0,0 +1,11 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Entities;
+
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider;
+
+class ServiceProvider extends AbstractProvider
+{
+}
diff --git a/src/Entities/User.php b/src/Entities/User.php
new file mode 100644
index 0000000..138bc4c
--- /dev/null
+++ b/src/Entities/User.php
@@ -0,0 +1,23 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Entities;
+
+class User
+{
+    protected array $attributes;
+
+    public function __construct(array $attributes)
+    {
+        $this->attributes = $attributes;
+    }
+
+    /**
+     * @return array
+     */
+    public function getAttributes(): array
+    {
+        return $this->attributes;
+    }
+}
diff --git a/src/Exceptions/Exception.php b/src/Exceptions/Exception.php
new file mode 100644
index 0000000..7a0306d
--- /dev/null
+++ b/src/Exceptions/Exception.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace SimpleSAML\Module\accounting\Exceptions;
+
+class Exception extends \Exception
+{
+}
diff --git a/src/Exceptions/InvalidConfigurationException.php b/src/Exceptions/InvalidConfigurationException.php
new file mode 100644
index 0000000..034624e
--- /dev/null
+++ b/src/Exceptions/InvalidConfigurationException.php
@@ -0,0 +1,11 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Exceptions;
+
+use ValueError;
+
+class InvalidConfigurationException extends ValueError
+{
+}
diff --git a/src/Exceptions/InvalidValueException.php b/src/Exceptions/InvalidValueException.php
new file mode 100644
index 0000000..c493285
--- /dev/null
+++ b/src/Exceptions/InvalidValueException.php
@@ -0,0 +1,11 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Exceptions;
+
+use ValueError;
+
+class InvalidValueException extends ValueError
+{
+}
diff --git a/src/Exceptions/StoreException.php b/src/Exceptions/StoreException.php
new file mode 100644
index 0000000..3e1b677
--- /dev/null
+++ b/src/Exceptions/StoreException.php
@@ -0,0 +1,11 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Exceptions;
+
+use Exception;
+
+class StoreException extends Exception
+{
+}
diff --git a/src/Exceptions/StoreException/MigrationException.php b/src/Exceptions/StoreException/MigrationException.php
new file mode 100644
index 0000000..377d06e
--- /dev/null
+++ b/src/Exceptions/StoreException/MigrationException.php
@@ -0,0 +1,11 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Exceptions\StoreException;
+
+use SimpleSAML\Module\accounting\Exceptions\StoreException;
+
+class MigrationException extends StoreException
+{
+}
diff --git a/src/Exceptions/UnexpectedValueException.php b/src/Exceptions/UnexpectedValueException.php
new file mode 100644
index 0000000..22fde53
--- /dev/null
+++ b/src/Exceptions/UnexpectedValueException.php
@@ -0,0 +1,9 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Exceptions;
+
+class UnexpectedValueException extends \UnexpectedValueException
+{
+}
diff --git a/src/Helpers/ArrayHelper.php b/src/Helpers/ArrayHelper.php
new file mode 100644
index 0000000..7aec51f
--- /dev/null
+++ b/src/Helpers/ArrayHelper.php
@@ -0,0 +1,20 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Helpers;
+
+class ArrayHelper
+{
+    public function recursivelySortByKey(array &$array): void
+    {
+        /** @psalm-suppress MixedAssignment */
+        foreach ($array as &$value) {
+            if (is_array($value)) {
+                $this->recursivelySortByKey($value);
+            }
+        }
+
+        ksort($array);
+    }
+}
diff --git a/src/Helpers/AttributesHelper.php b/src/Helpers/AttributesHelper.php
new file mode 100644
index 0000000..8fc6806
--- /dev/null
+++ b/src/Helpers/AttributesHelper.php
@@ -0,0 +1,35 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Helpers;
+
+class AttributesHelper
+{
+    /**
+     * Map files which translate attribute names to (more) user-friendly format.
+     */
+    public const MAP_FILES_TO_NAME = ['facebook2name.php', 'linkedin2name.php', 'oid2name.php', 'openid2name.php',
+        'removeurnprefix.php', 'twitter2name.php', 'urn2name.php', 'windowslive2name.php'];
+
+    public static function getMergedAttributeMapForFiles(string $sspBaseDirectory, array $mapFiles): array
+    {
+        // This is the variable name used in map files. It is set to empty array by default, but later populated
+        // by each include of the map file.
+        $attributemap = [];
+
+        $fullAttributeMap = [];
+
+        /** @var string $mapFile */
+        foreach ($mapFiles as $mapFile) {
+            $mapFilePath = $sspBaseDirectory . 'attributemap' . DIRECTORY_SEPARATOR . $mapFile;
+            if (! file_exists($mapFilePath)) {
+                continue;
+            }
+            include $mapFilePath;
+            $fullAttributeMap = array_merge($fullAttributeMap, $attributemap);
+        }
+
+        return $fullAttributeMap;
+    }
+}
diff --git a/src/Helpers/DateTimeHelper.php b/src/Helpers/DateTimeHelper.php
new file mode 100644
index 0000000..0fc5f25
--- /dev/null
+++ b/src/Helpers/DateTimeHelper.php
@@ -0,0 +1,27 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Helpers;
+
+class DateTimeHelper
+{
+    /**
+     * Convert date interval to seconds, interval being minimum 1 second.
+     * @param \DateInterval $dateInterval Minimum is 1 second.
+     * @return int
+     */
+    public function convertDateIntervalToSeconds(\DateInterval $dateInterval): int
+    {
+        $reference = new \DateTimeImmutable();
+        $endTime = $reference->add($dateInterval);
+
+        $duration = $endTime->getTimestamp() - $reference->getTimestamp();
+
+        if ($duration < 1) {
+            $duration = 1;
+        }
+
+        return $duration;
+    }
+}
diff --git a/src/Helpers/EnvironmentHelper.php b/src/Helpers/EnvironmentHelper.php
new file mode 100644
index 0000000..b67f33c
--- /dev/null
+++ b/src/Helpers/EnvironmentHelper.php
@@ -0,0 +1,11 @@
+<?php
+
+namespace SimpleSAML\Module\accounting\Helpers;
+
+class EnvironmentHelper
+{
+    public function isCli(): bool
+    {
+        return http_response_code() === false;
+    }
+}
diff --git a/src/Helpers/FilesystemHelper.php b/src/Helpers/FilesystemHelper.php
new file mode 100644
index 0000000..1ee6922
--- /dev/null
+++ b/src/Helpers/FilesystemHelper.php
@@ -0,0 +1,21 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Helpers;
+
+use SimpleSAML\Module\accounting\Exceptions\InvalidValueException;
+
+class FilesystemHelper
+{
+    public function getRealPath(string $path): string
+    {
+        $realpath = realpath($path);
+
+        if ($realpath === false || ! (is_dir($realpath) || is_file($realpath))) {
+            throw new InvalidValueException(sprintf('Given path can not be translated to real path (%s).', $path));
+        }
+
+        return $realpath;
+    }
+}
diff --git a/src/Helpers/HashHelper.php b/src/Helpers/HashHelper.php
new file mode 100644
index 0000000..ea38562
--- /dev/null
+++ b/src/Helpers/HashHelper.php
@@ -0,0 +1,26 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Helpers;
+
+class HashHelper
+{
+    protected ArrayHelper $arrayHelper;
+
+    public function __construct(ArrayHelper $arrayHelper)
+    {
+        $this->arrayHelper = $arrayHelper;
+    }
+
+    public function getSha256(string $data): string
+    {
+        return hash('sha256', $data);
+    }
+
+    public function getSha256ForArray(array $array): string
+    {
+        $this->arrayHelper->recursivelySortByKey($array);
+        return $this->getSha256(serialize($array));
+    }
+}
diff --git a/src/Helpers/InstanceBuilderUsingModuleConfigurationHelper.php b/src/Helpers/InstanceBuilderUsingModuleConfigurationHelper.php
new file mode 100644
index 0000000..fed3079
--- /dev/null
+++ b/src/Helpers/InstanceBuilderUsingModuleConfigurationHelper.php
@@ -0,0 +1,62 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Helpers;
+
+use Psr\Log\LoggerInterface;
+use ReflectionMethod;
+use SimpleSAML\Module\accounting\Exceptions\Exception;
+use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+use SimpleSAML\Module\accounting\Interfaces\BuildableUsingModuleConfigurationInterface;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+
+class InstanceBuilderUsingModuleConfigurationHelper
+{
+    /**
+     * @param class-string $class
+     * @param ModuleConfiguration $moduleConfiguration
+     * @param LoggerInterface $logger
+     * @param array $additionalArguments
+     * @param string $method
+     * @return BuildableUsingModuleConfigurationInterface
+     * @throws Exception
+     */
+    public function build(
+        string $class,
+        ModuleConfiguration $moduleConfiguration,
+        LoggerInterface $logger,
+        array $additionalArguments = [],
+        string $method = BuildableUsingModuleConfigurationInterface::BUILD_METHOD
+    ): BuildableUsingModuleConfigurationInterface {
+        try {
+            $this->validateClass($class);
+
+            $allArguments = array_merge([$moduleConfiguration, $logger], $additionalArguments);
+
+            $reflectionMethod = new ReflectionMethod($class, $method);
+            /** @var BuildableUsingModuleConfigurationInterface $instance */
+            $instance = $reflectionMethod->invoke(null, ...$allArguments);
+        } catch (\Throwable $exception) {
+            $message = \sprintf(
+                'Error building instance using module configuration. Error was: %s.',
+                $exception->getMessage()
+            );
+            throw new Exception($message, (int)$exception->getCode(), $exception);
+        }
+
+        return $instance;
+    }
+
+    protected function validateClass(string $class): void
+    {
+        if (!is_subclass_of($class, BuildableUsingModuleConfigurationInterface::class)) {
+            $message = sprintf(
+                'Class \'%s\' does not implement interface \'%s\'.',
+                $class,
+                BuildableUsingModuleConfigurationInterface::class
+            );
+            throw new UnexpectedValueException($message);
+        }
+    }
+}
diff --git a/src/Helpers/ModuleRoutesHelper.php b/src/Helpers/ModuleRoutesHelper.php
new file mode 100644
index 0000000..ed41487
--- /dev/null
+++ b/src/Helpers/ModuleRoutesHelper.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace SimpleSAML\Module\accounting\Helpers;
+
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Utils\HTTP;
+
+class ModuleRoutesHelper
+{
+    public const PATH_ADMIN_CONFIGURATION_STATUS = 'admin/configuration/status';
+
+    public const PATH_USER_PERSONAL_DATA = 'user/personal-data';
+
+    protected HTTP $sspHttpUtils;
+
+    public function __construct(HTTP $sspHttpUtils = null)
+    {
+        $this->sspHttpUtils = $sspHttpUtils ?? new HTTP();
+    }
+
+    public function getUrl(string $path, array $parameters = []): string
+    {
+        $url = $this->sspHttpUtils->getBaseURL() . 'module.php/' . ModuleConfiguration::MODULE_NAME . '/' . $path;
+
+        if (!empty($parameters)) {
+            $url = $this->sspHttpUtils->addURLParameters($url, $parameters);
+        }
+
+        return $url;
+    }
+}
diff --git a/src/Helpers/NetworkHelper.php b/src/Helpers/NetworkHelper.php
new file mode 100644
index 0000000..d7159a4
--- /dev/null
+++ b/src/Helpers/NetworkHelper.php
@@ -0,0 +1,32 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Helpers;
+
+class NetworkHelper
+{
+    public function resolveClientIpAddress(string $clientIpAddress = null): ?string
+    {
+        /** @var string|null $clientIpAddress */
+        $clientIpAddress = $clientIpAddress ??
+            $_SERVER['HTTP_CLIENT_IP'] ??
+            $_SERVER['HTTP_X_FORWARDED_FOR'] ??
+            $_SERVER['REMOTE_ADDR'] ??
+            null;
+
+        if (!is_string($clientIpAddress)) {
+            return null;
+        }
+
+        $ips = explode(',', $clientIpAddress);
+
+        $ip = mb_substr(trim(array_pop($ips)), 0, 45);
+
+        if (filter_var($ip, FILTER_VALIDATE_IP)) {
+            return $ip;
+        }
+
+        return null;
+    }
+}
diff --git a/src/Helpers/RandomHelper.php b/src/Helpers/RandomHelper.php
new file mode 100644
index 0000000..3a74a7f
--- /dev/null
+++ b/src/Helpers/RandomHelper.php
@@ -0,0 +1,19 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Helpers;
+
+class RandomHelper
+{
+    public function getRandomInt(int $minimum = PHP_INT_MIN, int $maximum = PHP_INT_MAX): int
+    {
+        try {
+            return random_int($minimum, $maximum);
+            // @codeCoverageIgnoreStart
+        } catch (\Throwable $exception) {
+            return mt_rand($minimum, $maximum);
+            // @codeCoverageIgnoreEnd
+        }
+    }
+}
diff --git a/src/Http/Controllers/Admin/Configuration.php b/src/Http/Controllers/Admin/Configuration.php
new file mode 100644
index 0000000..909518c
--- /dev/null
+++ b/src/Http/Controllers/Admin/Configuration.php
@@ -0,0 +1,126 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Http\Controllers\Admin;
+
+use Exception;
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Configuration as SspConfiguration;
+use SimpleSAML\Module\accounting\Helpers\ModuleRoutesHelper;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+use SimpleSAML\Module\accounting\Stores\Builders\JobsStoreBuilder;
+use SimpleSAML\Module\accounting\Trackers\Builders\AuthenticationDataTrackerBuilder;
+use SimpleSAML\Session;
+use SimpleSAML\Utils;
+use SimpleSAML\Utils\Auth;
+use SimpleSAML\XHTML\Template;
+use Symfony\Component\HttpFoundation\Request;
+use Throwable;
+
+class Configuration
+{
+    protected SspConfiguration $sspConfiguration;
+    protected Session $session;
+    protected LoggerInterface $logger;
+    protected Utils\Auth $sspAuthUtils;
+    protected HelpersManager $helpersManager;
+
+    public function __construct(
+        SspConfiguration $sspConfiguration,
+        Session $session,
+        LoggerInterface $logger,
+        HelpersManager $helpersManager,
+        Utils\Auth $sspAuthUtils = null
+    ) {
+        $this->sspConfiguration = $sspConfiguration;
+        $this->session = $session;
+        $this->logger = $logger;
+        $this->helpersManager = $helpersManager;
+        $this->sspAuthUtils = $sspAuthUtils ?? new Utils\Auth();
+
+        $this->sspAuthUtils->requireAdmin();
+    }
+
+    /**
+     * @param Request $request
+     * @return Template
+     * @throws Exception
+     */
+    public function status(Request $request): Template
+    {
+        // Instantiate ModuleConfiguration here (instead in constructor) so we can check for validation errors.
+        $moduleConfiguration = null;
+        $configurationValidationErrors = null;
+        $jobsStore = null;
+        $defaultDataTrackerAndProvider = null;
+        $additionalTrackers = [];
+        $setupNeeded = false;
+        $runSetup = $request->query->has('runSetup');
+
+        try {
+            $moduleConfiguration = new ModuleConfiguration();
+
+            $defaultDataTrackerAndProvider =
+                (new AuthenticationDataTrackerBuilder($moduleConfiguration, $this->logger, $this->helpersManager))
+                ->build($moduleConfiguration->getDefaultDataTrackerAndProviderClass());
+
+            if ($defaultDataTrackerAndProvider->needsSetup()) {
+                if ($runSetup) {
+                    $defaultDataTrackerAndProvider->runSetup();
+                } else {
+                    $setupNeeded = true;
+                }
+            }
+
+            if (
+                $moduleConfiguration->getAccountingProcessingType() ===
+                ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS
+            ) {
+                $jobsStore = (new JobsStoreBuilder($moduleConfiguration, $this->logger, $this->helpersManager))
+                    ->build($moduleConfiguration->getJobsStoreClass());
+                if ($jobsStore->needsSetup()) {
+                    if ($runSetup) {
+                        $jobsStore->runSetup();
+                    } else {
+                        $setupNeeded = true;
+                    }
+                }
+            }
+
+            foreach ($moduleConfiguration->getAdditionalTrackers() as $trackerClass) {
+                $additionalTrackerInstance =
+                    (new AuthenticationDataTrackerBuilder($moduleConfiguration, $this->logger, $this->helpersManager))
+                    ->build($trackerClass);
+
+                if ($additionalTrackerInstance->needsSetup()) {
+                    if ($runSetup) {
+                        $additionalTrackerInstance->runSetup();
+                    } else {
+                        $setupNeeded = true;
+                    }
+                }
+                $additionalTrackers[$trackerClass] = $additionalTrackerInstance;
+            }
+        } catch (Throwable $exception) {
+            $configurationValidationErrors = $exception->getMessage();
+        }
+
+        $templateData = [
+            'moduleConfiguration' => $moduleConfiguration,
+            'configurationValidationErrors' => $configurationValidationErrors,
+            'jobsStore' => $jobsStore,
+            'defaultDataTrackerAndProvider' => $defaultDataTrackerAndProvider,
+            'additionalTrackers' => $additionalTrackers,
+            'setupNeeded' => $setupNeeded,
+            'profilePageUri' => $this->helpersManager->getModuleRoutesHelper()
+                ->getUrl(ModuleRoutesHelper::PATH_USER_PERSONAL_DATA),
+        ];
+
+        $template = new Template($this->sspConfiguration, 'accounting:admin/configuration/status.twig');
+
+        $template->data = $templateData;
+        return $template;
+    }
+}
diff --git a/src/Http/Controllers/Test.php b/src/Http/Controllers/Test.php
new file mode 100644
index 0000000..e7b4446
--- /dev/null
+++ b/src/Http/Controllers/Test.php
@@ -0,0 +1,75 @@
+<?php
+// phpcs:ignoreFile
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Http\Controllers;
+
+use Exception;
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Configuration as SspConfiguration;
+use SimpleSAML\Locale\Translate;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event;
+use SimpleSAML\Module\accounting\Entities\Authentication\State;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+use SimpleSAML\Module\accounting\Stores\Builders\JobsStoreBuilder;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store;
+use SimpleSAML\Module\accounting\Trackers\Authentication\DoctrineDbal\Versioned\Tracker;
+use SimpleSAML\Module\accounting\Trackers\Builders\AuthenticationDataTrackerBuilder;
+use SimpleSAML\Session;
+use SimpleSAML\XHTML\Template;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * TODO mivanci delete this file before release
+ * @psalm-suppress all
+ */
+class Test
+{
+    protected SspConfiguration $sspConfiguration;
+    protected Session $session;
+    protected ModuleConfiguration $moduleConfiguration;
+    protected LoggerInterface $logger;
+    protected HelpersManager $helpersManager;
+
+    /**
+     * @param SspConfiguration $sspConfiguration
+     * @param Session $session The current user session.
+     * @param ModuleConfiguration $moduleConfiguration
+     * @param LoggerInterface $logger
+     */
+    public function __construct(
+        SspConfiguration $sspConfiguration,
+        Session $session,
+        ModuleConfiguration $moduleConfiguration,
+        LoggerInterface $logger,
+        HelpersManager $helpersManager
+    ) {
+        $this->sspConfiguration = $sspConfiguration;
+        $this->session = $session;
+        $this->moduleConfiguration = $moduleConfiguration;
+        $this->logger = $logger;
+        $this->helpersManager = $helpersManager;
+    }
+
+    /**
+     * @param Request $request
+     * @return Template
+     * @throws Exception
+     */
+    public function test(Request $request): Template
+    {
+        $template = new Template($this->sspConfiguration, 'accounting:test.twig');
+
+        $retentionPolicy = new \DateInterval('P4D');
+
+        (new AuthenticationDataTrackerBuilder($this->moduleConfiguration, $this->logger, $this->helpersManager))
+            ->build($this->moduleConfiguration->getDefaultDataTrackerAndProviderClass())
+            ->enforceDataRetentionPolicy($retentionPolicy);
+
+        die('end');
+
+        return $template;
+    }
+}
diff --git a/src/Http/Controllers/User/Profile.php b/src/Http/Controllers/User/Profile.php
new file mode 100644
index 0000000..aba52d9
--- /dev/null
+++ b/src/Http/Controllers/User/Profile.php
@@ -0,0 +1,191 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Http\Controllers\User;
+
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Auth\Simple;
+use SimpleSAML\Configuration as SspConfiguration;
+use SimpleSAML\HTTP\RunnableResponse;
+use SimpleSAML\Module\accounting\Exceptions\Exception;
+use SimpleSAML\Module\accounting\Helpers\AttributesHelper;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\ModuleConfiguration\ConnectionType;
+use SimpleSAML\Module\accounting\Providers\Builders\AuthenticationDataProviderBuilder;
+use SimpleSAML\Module\accounting\Providers\Interfaces\AuthenticationDataProviderInterface;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+use SimpleSAML\Session;
+use SimpleSAML\XHTML\Template;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+
+class Profile
+{
+    protected ModuleConfiguration $moduleConfiguration;
+    protected SspConfiguration $sspConfiguration;
+    protected Session $session;
+    protected LoggerInterface $logger;
+    protected string $defaultAuthenticationSource;
+    protected Simple $authSimple;
+    protected AuthenticationDataProviderBuilder $authenticationDataProviderBuilder;
+    protected HelpersManager $helpersManager;
+
+    /**
+     * @param ModuleConfiguration $moduleConfiguration
+     * @param SspConfiguration $sspConfiguration
+     * @param Session $session The current user session.
+     * @param LoggerInterface $logger
+     * @param Simple|null $authSimple
+     * @param AuthenticationDataProviderBuilder|null $authenticationDataProviderBuilder
+     * @param HelpersManager|null $helpersManager
+     */
+    public function __construct(
+        ModuleConfiguration $moduleConfiguration,
+        SspConfiguration $sspConfiguration,
+        Session $session,
+        LoggerInterface $logger,
+        Simple $authSimple = null,
+        AuthenticationDataProviderBuilder $authenticationDataProviderBuilder = null,
+        HelpersManager $helpersManager = null
+    ) {
+        $this->moduleConfiguration = $moduleConfiguration;
+        $this->sspConfiguration = $sspConfiguration;
+        $this->session = $session;
+        $this->logger = $logger;
+
+        $this->defaultAuthenticationSource = $moduleConfiguration->getDefaultAuthenticationSource();
+        $this->authSimple = $authSimple ?? new Simple($this->defaultAuthenticationSource, $sspConfiguration, $session);
+
+        $this->helpersManager = $helpersManager ?? new HelpersManager();
+
+        $this->authenticationDataProviderBuilder = $authenticationDataProviderBuilder ??
+            new AuthenticationDataProviderBuilder($this->moduleConfiguration, $this->logger, $this->helpersManager);
+
+        // Make sure the end user is authenticated.
+        $this->authSimple->requireAuth();
+    }
+
+    public function personalData(Request $request): Response
+    {
+        $normalizedAttributes = [];
+
+        $toNameAttributeMap = $this->prepareToNameAttributeMap();
+
+        /**
+         * @var string $name
+         * @var string[] $value
+         */
+        foreach ($this->authSimple->getAttributes() as $name => $value) {
+            // Convert attribute names to user-friendly names.
+            if (array_key_exists($name, $toNameAttributeMap)) {
+                $name = (string)$toNameAttributeMap[$name];
+            }
+            $normalizedAttributes[$name] = implode('; ', $value);
+        }
+
+        $template = $this->resolveTemplate('accounting:user/personal-data.twig');
+        $template->data = compact('normalizedAttributes');
+
+        return $template;
+    }
+
+    public function connectedOrganizations(Request $request): Template
+    {
+        $userIdentifier = $this->resolveUserIdentifier();
+
+        $authenticationDataProvider = $this->resolveAuthenticationDataProvider();
+
+        $this->removeDebugDisplayLimits();
+        $connectedServiceProviderBag = $authenticationDataProvider->getConnectedServiceProviders($userIdentifier);
+
+        $template = $this->resolveTemplate('accounting:user/connected-organizations.twig');
+        $template->data = compact('connectedServiceProviderBag');
+
+        return $template;
+    }
+
+    public function activity(Request $request): Template
+    {
+        $userIdentifier = $this->resolveUserIdentifier();
+
+        $authenticationDataProvider = $this->resolveAuthenticationDataProvider();
+
+        $page = ($page = (int)$request->query->get('page', 1)) > 0 ? $page : 1;
+
+        $maxResults = 10;
+        $firstResult = ($page - 1) * $maxResults;
+
+        $this->removeDebugDisplayLimits();
+        $activityBag = $authenticationDataProvider->getActivity($userIdentifier, $maxResults, $firstResult);
+
+        $template = $this->resolveTemplate('accounting:user/activity.twig');
+        $template->data = compact('activityBag', 'page', 'maxResults');
+
+        return $template;
+    }
+
+    protected function resolveUserIdentifier(): string
+    {
+        $attributes = $this->authSimple->getAttributes();
+        $idAttributeName = $this->moduleConfiguration->getUserIdAttributeName();
+
+        if (empty($attributes[$idAttributeName]) || !is_array($attributes[$idAttributeName])) {
+            $message = sprintf('No identifier %s present in user attributes.', $idAttributeName);
+            throw new Exception($message);
+        }
+
+        return (string)reset($attributes[$idAttributeName]);
+    }
+
+    /**
+     * @throws Exception
+     */
+    protected function resolveAuthenticationDataProvider(): AuthenticationDataProviderInterface
+    {
+        return $this->authenticationDataProviderBuilder
+            ->build(
+                $this->moduleConfiguration->getDefaultDataTrackerAndProviderClass(),
+                ConnectionType::SLAVE
+            );
+    }
+
+    public function logout(): Response
+    {
+        return new RunnableResponse([$this->authSimple, 'logout'], [$this->getLogoutUrl()]);
+    }
+
+    protected function getLogoutUrl(): string
+    {
+        return $this->sspConfiguration->getBasePath() . 'logout.php';
+    }
+
+    /**
+     * Load all attribute map files which translate attribute names to user-friendly name format.
+     */
+    protected function prepareToNameAttributeMap(): array
+    {
+        return $this->helpersManager->getAttributesHelper()->getMergedAttributeMapForFiles(
+            $this->sspConfiguration->getBaseDir(),
+            AttributesHelper::MAP_FILES_TO_NAME
+        );
+    }
+
+    /** TODO mivanci remove after debugging */
+    protected function removeDebugDisplayLimits(): void
+    {
+        ini_set('xdebug.var_display_max_depth', '-1');
+        ini_set('xdebug.var_display_max_children', '-1');
+        ini_set('xdebug.var_display_max_data', '-1');
+    }
+
+    protected function resolveTemplate(string $template): Template
+    {
+        $templateInstance = new Template($this->sspConfiguration, $template);
+
+        $templateInstance->getLocalization()->addModuleDomain(ModuleConfiguration::MODULE_NAME);
+        $templateInstance->getLocalization()->addAttributeDomains();
+
+        return $templateInstance;
+    }
+}
diff --git a/src/Interfaces/BuildableUsingModuleConfigurationInterface.php b/src/Interfaces/BuildableUsingModuleConfigurationInterface.php
new file mode 100644
index 0000000..c1a4aed
--- /dev/null
+++ b/src/Interfaces/BuildableUsingModuleConfigurationInterface.php
@@ -0,0 +1,13 @@
+<?php
+
+namespace SimpleSAML\Module\accounting\Interfaces;
+
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+
+interface BuildableUsingModuleConfigurationInterface
+{
+    public const BUILD_METHOD = 'build';
+
+    public static function build(ModuleConfiguration $moduleConfiguration, LoggerInterface $logger): self;
+}
diff --git a/src/Interfaces/SetupableInterface.php b/src/Interfaces/SetupableInterface.php
new file mode 100644
index 0000000..da036e1
--- /dev/null
+++ b/src/Interfaces/SetupableInterface.php
@@ -0,0 +1,9 @@
+<?php
+
+namespace SimpleSAML\Module\accounting\Interfaces;
+
+interface SetupableInterface
+{
+    public function needsSetup(): bool;
+    public function runSetup(): void;
+}
diff --git a/src/ModuleConfiguration.php b/src/ModuleConfiguration.php
new file mode 100644
index 0000000..fe83f63
--- /dev/null
+++ b/src/ModuleConfiguration.php
@@ -0,0 +1,488 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting;
+
+use DateInterval;
+use Exception;
+use SimpleSAML\Configuration;
+use SimpleSAML\Module\accounting\Exceptions\InvalidConfigurationException;
+use SimpleSAML\Module\accounting\ModuleConfiguration\AccountingProcessingType;
+use SimpleSAML\Module\accounting\ModuleConfiguration\ConnectionType;
+use SimpleSAML\Module\accounting\Providers\Interfaces\AuthenticationDataProviderInterface;
+use SimpleSAML\Module\accounting\Stores\Interfaces\JobsStoreInterface;
+use SimpleSAML\Module\accounting\Trackers\Interfaces\AuthenticationDataTrackerInterface;
+use Throwable;
+
+class ModuleConfiguration
+{
+    public const MODULE_NAME = 'accounting';
+
+    /**
+     * Default file name for module configuration. Can be overridden, for example, for testing purposes.
+     */
+    public const FILE_NAME = 'module_accounting.php';
+
+    public const OPTION_USER_ID_ATTRIBUTE_NAME = 'user_id_attribute_name';
+    public const OPTION_DEFAULT_AUTHENTICATION_SOURCE = 'default_authentication_source';
+    public const OPTION_ACCOUNTING_PROCESSING_TYPE = 'accounting_processing_type';
+    public const OPTION_JOBS_STORE = 'jobs_store';
+    public const OPTION_DEFAULT_DATA_TRACKER_AND_PROVIDER = 'default_data_tracker_and_provider';
+    public const OPTION_ADDITIONAL_TRACKERS = 'additional_trackers';
+    public const OPTION_CONNECTIONS_AND_PARAMETERS = 'connections_and_parameters';
+    public const OPTION_CLASS_TO_CONNECTION_MAP = 'class_to_connection_map';
+    public const OPTION_CRON_TAG_FOR_JOB_RUNNER = 'cron_tag_for_job_runner';
+    public const OPTION_JOB_RUNNER_MAXIMUM_EXECUTION_TIME = 'job_runner_maximum_execution_time';
+    public const OPTION_JOB_RUNNER_SHOULD_PAUSE_AFTER_NUMBER_OF_JOBS_PROCESSED =
+        'job_runner_should_pause_after_number_of_jobs_processed';
+    public const OPTION_TRACKER_DATA_RETENTION_POLICY = 'tracker_data_retention_policy';
+    public const OPTION_CRON_TAG_FOR_TRACKER_DATA_RETENTION_POLICY = 'cron_tag_for_tracker_data_retention_policy';
+
+    /**
+     * Contains configuration from module configuration file.
+     */
+    protected Configuration $configuration;
+
+    /**
+     * @throws Exception
+     */
+    public function __construct(string $fileName = null, array $overrides = [])
+    {
+        $fileName = $fileName ?? self::FILE_NAME;
+
+        $fullConfigArray = array_merge(Configuration::getConfig($fileName)->toArray(), $overrides);
+
+        $this->configuration = Configuration::loadFromArray($fullConfigArray);
+
+        $this->validate();
+    }
+
+    public function getAccountingProcessingType(): string
+    {
+        return $this->getConfiguration()->getString(self::OPTION_ACCOUNTING_PROCESSING_TYPE);
+    }
+
+    public function getCronTagForJobRunner(): string
+    {
+        return $this->getConfiguration()->getString(self::OPTION_CRON_TAG_FOR_JOB_RUNNER);
+    }
+
+    /**
+     * Get underlying SimpleSAMLphp Configuration instance.
+     *
+     * @return Configuration
+     */
+    public function getConfiguration(): Configuration
+    {
+        return $this->configuration;
+    }
+
+    public function getJobsStoreClass(): string
+    {
+        return $this->getConfiguration()->getString(self::OPTION_JOBS_STORE);
+    }
+
+    public function getJobRunnerMaximumExecutionTime(): ?DateInterval
+    {
+        $value = $this->get(self::OPTION_JOB_RUNNER_MAXIMUM_EXECUTION_TIME);
+
+        if (is_null($value)) {
+            return null;
+        }
+
+        if (! is_string($value)) {
+            $message = sprintf('Job runner maximum activity must be defined either as null, or DateInterval' .
+                               'duration (string).');
+            throw new InvalidConfigurationException($message);
+        }
+
+        try {
+            return new DateInterval($value);
+        } catch (Throwable $exception) {
+            $message = sprintf('Can not create DateInterval instance using value %s as parameter.', $value);
+            throw new InvalidConfigurationException($message);
+        }
+    }
+
+    public function getJobRunnerShouldPauseAfterNumberOfJobsProcessed(): ?int
+    {
+        $value = $this->get(self::OPTION_JOB_RUNNER_SHOULD_PAUSE_AFTER_NUMBER_OF_JOBS_PROCESSED);
+
+        if (is_null($value)) {
+            return null;
+        }
+
+        if (! is_int($value)) {
+            $message = sprintf(
+                'Option \'%s\' must be defined either as null, or positive integer.',
+                self::OPTION_JOB_RUNNER_SHOULD_PAUSE_AFTER_NUMBER_OF_JOBS_PROCESSED
+            );
+            throw new InvalidConfigurationException($message);
+        }
+
+        if ($value < 1) {
+            $message = sprintf(
+                'Option \'%s\' must positive integer.',
+                self::OPTION_JOB_RUNNER_SHOULD_PAUSE_AFTER_NUMBER_OF_JOBS_PROCESSED
+            );
+            throw new InvalidConfigurationException($message);
+        }
+
+        return $value;
+    }
+
+    public function getDefaultDataTrackerAndProviderClass(): string
+    {
+        return $this->getConfiguration()->getString(self::OPTION_DEFAULT_DATA_TRACKER_AND_PROVIDER);
+    }
+
+    public function getConnectionsAndParameters(): array
+    {
+        return $this->getConfiguration()->getArray(self::OPTION_CONNECTIONS_AND_PARAMETERS);
+    }
+
+    /**
+     * @return string[]
+     * @psalm-suppress MixedReturnTypeCoercion We specifically check if valid class string are provided.
+     */
+    public function getAdditionalTrackers(): array
+    {
+        return $this->getConfiguration()->getArray(self::OPTION_ADDITIONAL_TRACKERS);
+    }
+
+    public function getClassToConnectionsMap(): array
+    {
+        return $this->getConfiguration()->getArray(self::OPTION_CLASS_TO_CONNECTION_MAP);
+    }
+
+    /**
+     * Get configuration option from module configuration file.
+     *
+     * @param string $option
+     * @return mixed
+     */
+    public function get(string $option)
+    {
+        if (!$this->configuration->hasValue($option)) {
+            throw new InvalidConfigurationException(
+                sprintf('Configuration option does not exist (%s).', $option)
+            );
+        }
+
+        return $this->configuration->getValue($option);
+    }
+
+    public function getUserIdAttributeName(): string
+    {
+        return $this->getConfiguration()->getString(self::OPTION_USER_ID_ATTRIBUTE_NAME);
+    }
+
+    public function getDefaultAuthenticationSource(): string
+    {
+        return $this->getConfiguration()->getString(self::OPTION_DEFAULT_AUTHENTICATION_SOURCE);
+    }
+
+    public function getClassConnectionKey(string $class, string $connectionType = ConnectionType::MASTER): string
+    {
+        $this->validateConnectionType($connectionType);
+
+        $connections = $this->getClassToConnectionsMap();
+
+        if (!isset($connections[$class])) {
+            throw new InvalidConfigurationException(sprintf('Connection for class \'%s\' not set.', $class));
+        }
+
+        $connectionValue = $connections[$class];
+
+        // If the key is defined directly, return that.
+        if (is_string($connectionValue)) {
+            return $connectionValue;
+        }
+
+        if (!is_array($connectionValue)) {
+            throw new InvalidConfigurationException(
+                sprintf('Connection for class \'%s\' is not defined as string nor as array.', $class)
+            );
+        }
+
+        if (!isset($connectionValue[ConnectionType::MASTER])) {
+            $message = sprintf(
+                'Connection for class \'%s\' is defined as array, however no master connection key is set.',
+                $class
+            );
+            throw new InvalidConfigurationException($message);
+        }
+
+        // By default, use master connection key.
+        $connectionKey = (string)$connectionValue[ConnectionType::MASTER];
+
+        if ($connectionType === ConnectionType::MASTER || (! isset($connectionValue[ConnectionType::SLAVE]))) {
+            return $connectionKey;
+        }
+
+        if (is_array($connectionValue[ConnectionType::SLAVE])) {
+            // Return random slave connection key.
+            $slaveConnections = $connectionValue[ConnectionType::SLAVE];
+            $connectionKey = (string)$slaveConnections[array_rand($slaveConnections)];
+        }
+
+        return $connectionKey;
+    }
+
+    /**
+     * @throws InvalidConfigurationException
+     */
+    public function getClassConnectionParameters(string $class, string $connectionType = ConnectionType::MASTER): array
+    {
+        return $this->getConnectionParameters($this->getClassConnectionKey($class, $connectionType));
+    }
+
+    /**
+     * @throws InvalidConfigurationException
+     */
+    public function getConnectionParameters(string $connectionKey): array
+    {
+        $connections = $this->getConnectionsAndParameters();
+
+        if (!isset($connections[$connectionKey]) || !is_array($connections[$connectionKey])) {
+            throw new InvalidConfigurationException(
+                sprintf('Connection parameters not set for key \'%s\'.', $connectionKey)
+            );
+        }
+
+        return $connections[$connectionKey];
+    }
+
+    public function getModuleSourceDirectory(): string
+    {
+        return __DIR__;
+    }
+
+    public function getModuleRootDirectory(): string
+    {
+        return dirname(__DIR__);
+    }
+
+    /**
+     * @throws InvalidConfigurationException
+     */
+    protected function validate(): void
+    {
+        $errors = [];
+
+        try {
+            $this->validateAccountingProcessingType();
+        } catch (Throwable $exception) {
+            $errors[] = $exception->getMessage();
+        }
+
+        // If accounting processing type is async, validate jobs store class and connection.
+        if ($this->getAccountingProcessingType() === AccountingProcessingType::VALUE_ASYNCHRONOUS) {
+            try {
+                $this->validateJobsStoreClass();
+                $this->validateCronTagForJobRunner();
+            } catch (Throwable $exception) {
+                $errors[] = $exception->getMessage();
+            }
+        }
+
+        try {
+            $this->validateDefaultDataTrackerAndProvider();
+        } catch (Throwable $exception) {
+            $errors[] = $exception->getMessage();
+        }
+
+        try {
+            $this->validateAdditionalTrackers();
+        } catch (Throwable $exception) {
+            $errors[] = $exception->getMessage();
+        }
+
+        try {
+            $this->validateClassToConnectionMap();
+        } catch (Throwable $exception) {
+            $errors[] = $exception->getMessage();
+        }
+
+        try {
+            $this->validateTrackerDataRetentionPolicy();
+        } catch (Throwable $exception) {
+            $errors[] = $exception->getMessage();
+        }
+
+
+        if (!empty($errors)) {
+            $message = sprintf('Module configuration validation failed with errors: %s', implode(' ', $errors));
+            throw new InvalidConfigurationException($message);
+        }
+    }
+
+    /**
+     * @throws InvalidConfigurationException
+     */
+    protected function validateDefaultDataTrackerAndProvider(): void
+    {
+        $errors = [];
+
+        // Default data tracker and provider must implement proper interfaces.
+        $defaultDataTrackerAndProviderClass = $this->getDefaultDataTrackerAndProviderClass();
+
+        if (!is_subclass_of($defaultDataTrackerAndProviderClass, AuthenticationDataTrackerInterface::class)) {
+            $errors[] = sprintf(
+                'Default authentication data tracker and provider class \'%s\' does not implement interface \'%s\'.',
+                $defaultDataTrackerAndProviderClass,
+                AuthenticationDataTrackerInterface::class
+            );
+        }
+
+        if (!is_subclass_of($defaultDataTrackerAndProviderClass, AuthenticationDataProviderInterface::class)) {
+            $errors[] = sprintf(
+                'Default authentication data tracker and provider class \'%s\' does not implement interface \'%s\'.',
+                $defaultDataTrackerAndProviderClass,
+                AuthenticationDataProviderInterface::class
+            );
+        }
+
+        if (!empty($errors)) {
+            throw new InvalidConfigurationException(implode(' ', $errors));
+        }
+    }
+
+    /**
+     * @throws InvalidConfigurationException
+     */
+    protected function validateAdditionalTrackers(): void
+    {
+        $errors = [];
+
+        // Validate additional trackers
+        foreach ($this->getAdditionalTrackers() as $trackerClass) {
+            /** @psalm-suppress DocblockTypeContradiction */
+            if (!is_string($trackerClass)) {
+                $errors[] = 'Additional trackers array must contain class strings only.';
+            } elseif (!is_subclass_of($trackerClass, AuthenticationDataTrackerInterface::class)) {
+                $errors[] = sprintf(
+                    'Tracker class \'%s\' does not implement interface \'%s\'.',
+                    $trackerClass,
+                    AuthenticationDataTrackerInterface::class
+                );
+            }
+        }
+
+        if (!empty($errors)) {
+            throw new InvalidConfigurationException(implode(' ', $errors));
+        }
+    }
+
+    /**
+     * @throws InvalidConfigurationException
+     */
+    protected function validateConnectionType(string $connectionType): void
+    {
+        if (!in_array($connectionType, ConnectionType::VALID_OPTIONS)) {
+            $message = sprintf(
+                'Connection type \'%s\' is not valid. Possible values are: %s.',
+                $connectionType,
+                implode(', ', ConnectionType::VALID_OPTIONS)
+            );
+            throw new InvalidConfigurationException($message);
+        }
+    }
+
+    /**
+     * @throws InvalidConfigurationException
+     */
+    protected function validateAccountingProcessingType(): void
+    {
+        // Only defined accounting processing types are allowed.
+        if (!in_array($this->getAccountingProcessingType(), AccountingProcessingType::VALID_OPTIONS)) {
+            $message = sprintf(
+                'Accounting processing type is not valid; possible values are: %s.',
+                implode(', ', AccountingProcessingType::VALID_OPTIONS)
+            );
+
+            throw new InvalidConfigurationException($message);
+        }
+    }
+
+    /**
+     * @throws InvalidConfigurationException
+     */
+    protected function validateJobsStoreClass(): void
+    {
+        // Jobs store class must implement JobsStoreInterface
+        $jobsStore = $this->getJobsStoreClass();
+        if (!class_exists($jobsStore) || !is_subclass_of($jobsStore, JobsStoreInterface::class)) {
+            $message = sprintf(
+                'Provided jobs store class \'%s\' does not implement interface \'%s\'.',
+                $jobsStore,
+                JobsStoreInterface::class
+            );
+
+            throw new InvalidConfigurationException($message);
+        }
+    }
+
+    /**
+     * @throws InvalidConfigurationException
+     */
+    protected function validateClassToConnectionMap(): void
+    {
+        $errors = [];
+
+        $connectionsAndParameters = $this->getConnectionsAndParameters();
+        // Each defined class should have defined connection parameters.
+        $classToConnectionMap = array_keys($this->getClassToConnectionsMap());
+        /** @var string $class */
+        foreach ($classToConnectionMap as $class) {
+            $connectionKey = $this->getClassConnectionKey($class);
+            if (! array_key_exists($connectionKey, $connectionsAndParameters)) {
+                $errors[] = sprintf(
+                    'Class \'%s\' has connection key \'%s\' set, however parameters for that key are not set.',
+                    $class,
+                    $connectionKey
+                );
+            }
+        }
+
+        if (!empty($errors)) {
+            throw new InvalidConfigurationException(implode(' ', $errors));
+        }
+    }
+
+    protected function validateCronTagForJobRunner(): void
+    {
+        $this->getCronTagForJobRunner();
+    }
+
+    protected function validateTrackerDataRetentionPolicy(): void
+    {
+        if ($this->getTrackerDataRetentionPolicy() !== null) {
+            $this->getCronTagForTrackerDataRetentionPolicy();
+        }
+    }
+
+    public function getTrackerDataRetentionPolicy(): ?DateInterval
+    {
+        /** @var string|null $value */
+        $value = $this->getConfiguration()
+            ->getOptionalString(self::OPTION_TRACKER_DATA_RETENTION_POLICY, null);
+
+        if (is_null($value)) {
+            return null;
+        }
+
+        try {
+            return new DateInterval($value);
+        } catch (Throwable $exception) {
+            $message = sprintf('Can not create DateInterval instance using value %s as parameter.', $value);
+            throw new InvalidConfigurationException($message);
+        }
+    }
+
+    public function getCronTagForTrackerDataRetentionPolicy(): string
+    {
+        return $this->getConfiguration()->getString(self::OPTION_CRON_TAG_FOR_TRACKER_DATA_RETENTION_POLICY);
+    }
+}
diff --git a/src/ModuleConfiguration/AccountingProcessingType.php b/src/ModuleConfiguration/AccountingProcessingType.php
new file mode 100644
index 0000000..fef0718
--- /dev/null
+++ b/src/ModuleConfiguration/AccountingProcessingType.php
@@ -0,0 +1,16 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\ModuleConfiguration;
+
+final class AccountingProcessingType
+{
+    public const VALUE_SYNCHRONOUS = 'synchronous';
+    public const VALUE_ASYNCHRONOUS = 'asynchronous';
+
+    public const VALID_OPTIONS = [
+        self::VALUE_SYNCHRONOUS,
+        self::VALUE_ASYNCHRONOUS,
+    ];
+}
diff --git a/src/ModuleConfiguration/ConnectionType.php b/src/ModuleConfiguration/ConnectionType.php
new file mode 100644
index 0000000..0ad53b8
--- /dev/null
+++ b/src/ModuleConfiguration/ConnectionType.php
@@ -0,0 +1,16 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\ModuleConfiguration;
+
+final class ConnectionType
+{
+    public const MASTER = 'master';
+    public const SLAVE = 'slave';
+
+    public const VALID_OPTIONS = [
+        self::MASTER,
+        self::SLAVE,
+    ];
+}
diff --git a/src/Providers/Builders/AuthenticationDataProviderBuilder.php b/src/Providers/Builders/AuthenticationDataProviderBuilder.php
new file mode 100644
index 0000000..b064f1c
--- /dev/null
+++ b/src/Providers/Builders/AuthenticationDataProviderBuilder.php
@@ -0,0 +1,65 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Providers\Builders;
+
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Module\accounting\Exceptions\Exception;
+use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+use SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfigurationHelper;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Providers\Interfaces\AuthenticationDataProviderInterface;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+use Throwable;
+
+class AuthenticationDataProviderBuilder
+{
+    protected ModuleConfiguration $moduleConfiguration;
+    protected LoggerInterface $logger;
+    protected HelpersManager $helpersManager;
+
+    public function __construct(
+        ModuleConfiguration $moduleConfiguration,
+        LoggerInterface $logger,
+        HelpersManager $helpersManager
+    ) {
+        $this->moduleConfiguration = $moduleConfiguration;
+        $this->logger = $logger;
+        $this->helpersManager = $helpersManager;
+    }
+
+    /**
+     * @throws Exception
+     */
+    public function build(
+        string $class,
+        string $connectionType = ModuleConfiguration\ConnectionType::MASTER
+    ): AuthenticationDataProviderInterface {
+        try {
+            // Make sure that the class implements proper interface
+            if (!is_subclass_of($class, AuthenticationDataProviderInterface::class)) {
+                $message = sprintf(
+                    'Class %s does not implement interface %s.',
+                    $class,
+                    AuthenticationDataProviderInterface::class
+                );
+                throw new UnexpectedValueException($message);
+            }
+
+            // Build...
+            /** @var AuthenticationDataProviderInterface $store */
+            $store = $this->helpersManager->getInstanceBuilderUsingModuleConfigurationHelper()->build(
+                $class,
+                $this->moduleConfiguration,
+                $this->logger,
+                [$connectionType]
+            );
+        } catch (Throwable $exception) {
+            $message = sprintf('Error building instance for class %s. Error was: %s', $class, $exception->getMessage());
+            throw new Exception($message, (int)$exception->getCode(), $exception);
+        }
+
+        return $store;
+    }
+}
diff --git a/src/Providers/Interfaces/AuthenticationDataProviderInterface.php b/src/Providers/Interfaces/AuthenticationDataProviderInterface.php
new file mode 100644
index 0000000..8c60297
--- /dev/null
+++ b/src/Providers/Interfaces/AuthenticationDataProviderInterface.php
@@ -0,0 +1,24 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Providers\Interfaces;
+
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Module\accounting\Entities\Activity;
+use SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider;
+use SimpleSAML\Module\accounting\Interfaces\BuildableUsingModuleConfigurationInterface;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+
+interface AuthenticationDataProviderInterface extends BuildableUsingModuleConfigurationInterface
+{
+    public static function build(
+        ModuleConfiguration $moduleConfiguration,
+        LoggerInterface $logger,
+        string $connectionType = ModuleConfiguration\ConnectionType::MASTER
+    ): self;
+
+    public function getConnectedServiceProviders(string $userIdentifier): ConnectedServiceProvider\Bag;
+
+    public function getActivity(string $userIdentifier, int $maxResults, int $firstResult): Activity\Bag;
+}
diff --git a/src/Services/HelpersManager.php b/src/Services/HelpersManager.php
new file mode 100644
index 0000000..e66518f
--- /dev/null
+++ b/src/Services/HelpersManager.php
@@ -0,0 +1,80 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Services;
+
+use SimpleSAML\Module\accounting\Helpers\ArrayHelper;
+use SimpleSAML\Module\accounting\Helpers\AttributesHelper;
+use SimpleSAML\Module\accounting\Helpers\DateTimeHelper;
+use SimpleSAML\Module\accounting\Helpers\EnvironmentHelper;
+use SimpleSAML\Module\accounting\Helpers\FilesystemHelper;
+use SimpleSAML\Module\accounting\Helpers\HashHelper;
+use SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfigurationHelper;
+use SimpleSAML\Module\accounting\Helpers\NetworkHelper;
+use SimpleSAML\Module\accounting\Helpers\RandomHelper;
+use SimpleSAML\Module\accounting\Helpers\ModuleRoutesHelper;
+
+class HelpersManager
+{
+    protected static ?DateTimeHelper $dateTimeHelper;
+    protected static ?EnvironmentHelper $environmentHelper;
+    protected static ?RandomHelper $randomHelper;
+    protected static ?ModuleRoutesHelper $routesHelper;
+    protected static ?ArrayHelper $arrayHelper;
+    protected static ?HashHelper $hashHelper;
+    protected static ?AttributesHelper $attributesHelper;
+    protected static ?FilesystemHelper $filesystemHelper;
+    protected static ?InstanceBuilderUsingModuleConfigurationHelper $instanceBuilderHelper;
+    protected static ?NetworkHelper $networkHelper;
+
+    public function getDateTimeHelper(): DateTimeHelper
+    {
+        return self::$dateTimeHelper ??= new DateTimeHelper();
+    }
+
+    public function getEnvironmentHelper(): EnvironmentHelper
+    {
+        return self::$environmentHelper ??= new EnvironmentHelper();
+    }
+
+    public function getRandomHelper(): RandomHelper
+    {
+        return self::$randomHelper ??= new RandomHelper();
+    }
+
+    public function getModuleRoutesHelper(): ModuleRoutesHelper
+    {
+        return self::$routesHelper ??= new ModuleRoutesHelper();
+    }
+
+    public function getArrayHelper(): ArrayHelper
+    {
+        return self::$arrayHelper ??= new ArrayHelper();
+    }
+
+    public function getHashHelper(): HashHelper
+    {
+        return self::$hashHelper ??= new HashHelper($this->getArrayHelper());
+    }
+
+    public function getAttributesHelper(): AttributesHelper
+    {
+        return self::$attributesHelper ??= new AttributesHelper();
+    }
+
+    public function getFilesystemHelper(): FilesystemHelper
+    {
+        return self::$filesystemHelper ??= new FilesystemHelper();
+    }
+
+    public function getInstanceBuilderUsingModuleConfigurationHelper(): InstanceBuilderUsingModuleConfigurationHelper
+    {
+        return self::$instanceBuilderHelper ??= new InstanceBuilderUsingModuleConfigurationHelper();
+    }
+
+    public function getNetworkHelper(): NetworkHelper
+    {
+        return self::$networkHelper ??= new NetworkHelper();
+    }
+}
diff --git a/src/Services/JobRunner.php b/src/Services/JobRunner.php
new file mode 100644
index 0000000..b08d96f
--- /dev/null
+++ b/src/Services/JobRunner.php
@@ -0,0 +1,599 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Services;
+
+use Cicnavi\SimpleFileCache\SimpleFileCache;
+use Psr\Log\LoggerInterface;
+use Psr\SimpleCache\CacheInterface;
+use Psr\SimpleCache\InvalidArgumentException;
+use SimpleSAML\Configuration as SspConfiguration;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event\Job;
+use SimpleSAML\Module\accounting\Exceptions\Exception;
+use SimpleSAML\Module\accounting\Exceptions\StoreException;
+use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Services\JobRunner\RateLimiter;
+use SimpleSAML\Module\accounting\Services\JobRunner\State;
+use SimpleSAML\Module\accounting\Stores\Builders\JobsStoreBuilder;
+use SimpleSAML\Module\accounting\Trackers\Builders\AuthenticationDataTrackerBuilder;
+use SimpleSAML\Module\accounting\Trackers\Interfaces\AuthenticationDataTrackerInterface;
+
+class JobRunner
+{
+    protected ModuleConfiguration $moduleConfiguration;
+    protected SspConfiguration $sspConfiguration;
+    protected LoggerInterface $logger;
+    protected AuthenticationDataTrackerBuilder $authenticationDataTrackerBuilder;
+    protected JobsStoreBuilder $jobsStoreBuilder;
+    protected CacheInterface $cache;
+    protected State $state;
+
+    protected const CACHE_NAME = 'accounting-job-runner-cache';
+    protected const CACHE_KEY_STATE = 'state';
+
+    /**
+     * Interval after which the state will be considered stale.
+     */
+    public const STATE_STALE_THRESHOLD_INTERVAL = 'PT5M';
+
+    /**
+     * @var int $jobRunnerId ID of the current job runner instance.
+     */
+    protected int $jobRunnerId;
+    protected array $trackers;
+    protected \DateInterval $stateStaleThresholdInterval;
+    protected RateLimiter $rateLimiter;
+    protected HelpersManager $helpersManager;
+    protected ?\DateInterval $maximumExecutionTime;
+    protected ?int $shouldPauseAfterNumberOfJobsProcessed;
+
+    public function __construct(
+        ModuleConfiguration $moduleConfiguration,
+        SspConfiguration $sspConfiguration,
+        LoggerInterface $logger = null,
+        HelpersManager $helpersManager = null,
+        AuthenticationDataTrackerBuilder $authenticationDataTrackerBuilder = null,
+        JobsStoreBuilder $jobsStoreBuilder = null,
+        CacheInterface $cache = null,
+        State $state = null,
+        RateLimiter $rateLimiter = null
+    ) {
+        $this->moduleConfiguration = $moduleConfiguration;
+        $this->sspConfiguration = $sspConfiguration;
+        $this->logger = $logger ?? new Logger();
+        $this->helpersManager = $helpersManager ?? new HelpersManager();
+
+        $this->authenticationDataTrackerBuilder = $authenticationDataTrackerBuilder ??
+            new AuthenticationDataTrackerBuilder($this->moduleConfiguration, $this->logger, $this->helpersManager);
+        $this->jobsStoreBuilder = $jobsStoreBuilder ??
+            new JobsStoreBuilder($this->moduleConfiguration, $this->logger, $this->helpersManager);
+
+        $this->cache = $cache ?? $this->resolveCache();
+
+        $this->jobRunnerId = $this->helpersManager->getRandomHelper()->getRandomInt();
+
+        $this->state = $state ?? new State($this->jobRunnerId);
+
+        $this->trackers = $this->resolveTrackers();
+        $this->stateStaleThresholdInterval = new \DateInterval(self::STATE_STALE_THRESHOLD_INTERVAL);
+        $this->rateLimiter = $rateLimiter ?? new RateLimiter();
+
+        $this->maximumExecutionTime = $this->resolveMaximumExecutionTime();
+        $this->shouldPauseAfterNumberOfJobsProcessed =
+            $this->moduleConfiguration->getJobRunnerShouldPauseAfterNumberOfJobsProcessed();
+
+        $this->registerInterruptHandler();
+    }
+
+    /**
+     * @throws Exception|StoreException
+     */
+    public function run(): State
+    {
+        try {
+            $this->validatePreRunState();
+        } catch (\Throwable $exception) {
+            $message = sprintf(
+                'Pre-run state validation failed. Clearing cached state and continuing. Error was %s',
+                $exception->getMessage()
+            );
+            $this->logger->warning($message);
+            $this->state->addStatusMessage($message);
+            $this->clearCachedState();
+        }
+
+        try {
+            $this->validateRunConditions();
+        } catch (\Throwable $exception) {
+            $message = sprintf('Run conditions are not met, stopping. Reason was: %s', $exception->getMessage());
+            $this->logger->info($message);
+            $this->state->addStatusMessage($message);
+            return $this->state;
+        }
+
+        $this->logger->debug('Run conditions validated.');
+
+        $this->initializeCachedState();
+
+        $jobsStore = $this->jobsStoreBuilder->build($this->moduleConfiguration->getJobsStoreClass());
+
+        $jobsProcessedSincePause = 0;
+
+        // We have a clean state, we can start processing.
+        while ($this->shouldRun()) {
+            try {
+                /** @var ?Job $job */
+                $job = $jobsStore->dequeue(Job::class);
+
+                $this->updateCachedState($this->state);
+
+                declare(ticks=1) {
+                    // No new jobs at the moment....
+                    if ($job === null) {
+                        $this->state->addStatusMessage('No (more) jobs to process.');
+                        // If in CLI, do the backoff pause, so we can continue working later.
+                        if ($this->isCli()) {
+                            $message = sprintf(
+                                'Doing a backoff pause for %s seconds.',
+                                $this->rateLimiter->getCurrentBackoffPauseInSeconds()
+                            );
+                            $this->logger->debug($message);
+                            $this->state->addStatusMessage($message);
+                            $this->rateLimiter->doBackoffPause();
+                            $jobsProcessedSincePause = 0;
+                            continue;
+                        } else {
+                            // Since this is a web run, we will break immediately, so we can return HTTP response.
+                            break;
+                        }
+                    }
+
+                    // We have a job...
+                    $this->rateLimiter->resetBackoffPause();
+                }
+
+                /** @var AuthenticationDataTrackerInterface $tracker */
+                foreach ($this->trackers as $tracker) {
+                    /** @var Job $job */
+                    $tracker->process($job->getPayload());
+                }
+
+                $this->state->incrementSuccessfulJobsProcessed();
+
+                /** @var Job $job */
+                $successMessage = sprintf(
+                    'Successfully processed job with ID %s.',
+                    $job->getId() ?? '(N/A)'
+                );
+                $this->logger->debug($successMessage);
+                $this->state->addStatusMessage($successMessage);
+
+                // If the job runner friendly pausing is enabled, and if the number of jobs processed since the last
+                // pause is greater than the configured value, do the pause.
+                if (
+                    $this->shouldPauseAfterNumberOfJobsProcessed !== null &&
+                    $jobsProcessedSincePause > $this->shouldPauseAfterNumberOfJobsProcessed
+                ) {
+                    $this->rateLimiter->doPause();
+                    $jobsProcessedSincePause = 0;
+                } else {
+                    $jobsProcessedSincePause++;
+                }
+            } catch (\Throwable $exception) {
+                $message = sprintf('Error while processing jobs. Error was: %', $exception->getMessage());
+                $context = [];
+                if (isset($job)) {
+                    $context = ['job' => $job];
+                    $jobsStore->markFailedJob($job);
+                }
+                $this->logger->error($message, $context);
+                $this->state->incrementFailedJobsProcessed();
+                $this->state->addStatusMessage($message);
+            }
+        }
+
+        $this->clearCachedState();
+
+        $this->state->setEndedAt(new \DateTimeImmutable());
+        return $this->state;
+    }
+
+    /**
+     */
+    protected function shouldRun(): bool
+    {
+        // Enable this code to tick, which will enable it to catch CTRL-C signals and stop gracefully.
+        declare(ticks=1) {
+            if ($this->isMaximumExecutionTimeReached()) {
+                $message = 'Maximum job runner execution time reached.';
+                $this->logger->debug($message);
+                $this->state->addStatusMessage($message);
+                return false;
+            }
+
+            if ($this->state->getTotalJobsProcessed() > (PHP_INT_MAX - 1)) {
+                $message = 'Maximum number of processed jobs reached.';
+                $this->logger->debug($message);
+                $this->state->addStatusMessage($message);
+                return false;
+            }
+
+            try {
+                $this->validateSelfState();
+            } catch (\Throwable $exception) {
+                $message = sprintf(
+                    'Job runner state is not valid. Message was: %s',
+                    $exception->getMessage()
+                );
+                $this->logger->warning($message);
+                $this->state->addStatusMessage($message);
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * @throws Exception
+     */
+    protected function initializeCachedState(): void
+    {
+        // Make sure that the state does not exist in the cache.
+        try {
+            if ($this->getCachedState() !== null) {
+                throw new UnexpectedValueException('Job runner state already initialized.');
+            }
+        } catch (\Throwable $exception) {
+            $message = sprintf('Error initializing job runner state. Error was: %s.', $exception->getMessage());
+            $this->logger->error($message);
+            throw new Exception($message, (int)$exception->getCode(), $exception);
+        }
+
+        $startedAt = new \DateTimeImmutable();
+        $this->state->setStartedAt($startedAt);
+        $this->updateCachedState($this->state, $startedAt);
+    }
+
+    /**
+     * @throws Exception
+     */
+    protected function validatePreRunState(): void
+    {
+        $cachedState = $this->getCachedState();
+
+        // Empty state means that no other job runner is active.
+        if ($cachedState === null) {
+            return;
+        }
+
+        if ($cachedState->getJobRunnerId() === $this->jobRunnerId) {
+            $message = 'Job runner ID in cached state same as new ID.';
+            $this->logger->error($message);
+            throw new Exception($message);
+        }
+
+        if ($cachedState->isStale($this->stateStaleThresholdInterval)) {
+            $message = 'Stale state encountered.';
+            $this->logger->warning($message);
+            throw new Exception($message);
+        }
+    }
+
+    /**
+     * @throws Exception
+     */
+    protected function validateSelfState(): void
+    {
+        $cachedState = $this->getCachedState();
+
+        // Validate state before start.
+        if ($this->state->hasRunStarted() === false) {
+            if ($cachedState !== null) {
+                $message = 'Job run has not started, however cached state has already been initialized.';
+                throw new Exception($message);
+            }
+        }
+
+        // Validate state after start.
+        if ($this->state->hasRunStarted() === true) {
+            if ($cachedState === null) {
+                $message = 'Job run has started, however cached state has not been initialized.';
+                throw new Exception($message);
+            }
+
+            if ($cachedState->getJobRunnerId() !== $this->jobRunnerId) {
+                $message = 'Current job runner ID differs from the ID in the cached state.';
+                throw new Exception($message);
+            }
+
+            if ($cachedState->isStale($this->stateStaleThresholdInterval)) {
+                $message = 'Job runner cached state is stale, which means possible job runner process shutdown' .
+                    ' without cached state clearing.';
+                throw new Exception($message);
+            }
+
+            if ($cachedState->getIsGracefulInterruptInitiated()) {
+                $message = 'Graceful job processing interrupt initiated.';
+                throw new Exception($message);
+            }
+        }
+    }
+
+    protected function isAnotherJobRunnerActive(): bool
+    {
+        try {
+            $cachedState = $this->getCachedState();
+
+            if ($cachedState === null) {
+                return false;
+            }
+
+            // There is cached state, which would indicate that a job runner is active. However, make sure that the
+            // state is not stale (which indicates that the runner was shutdown without state clearing). If stale,
+            // this means that the job runner is not active.
+            if ($cachedState->isStale($this->stateStaleThresholdInterval)) {
+                $this->logger->warning('Stale cache encountered. Assuming no job runner is active.');
+                return false;
+            }
+
+            return $cachedState->getJobRunnerId() !== $this->jobRunnerId;
+        } catch (\Throwable $exception) {
+            $message = sprintf(
+                'Error checking if another job runner is active. To play safe, we will assume true. ' .
+                'Error was: %s',
+                $exception->getMessage()
+            );
+            $this->logger->error($message);
+            return true;
+        }
+    }
+
+    /**
+     * @throws Exception
+     */
+    protected function resolveCache(): SimpleFileCache
+    {
+        try {
+            $this->logger->debug('Trying to initialize job runner cache using SSP datadir.');
+            $cache = new SimpleFileCache(
+                self::CACHE_NAME,
+                $this->sspConfiguration->getPathValue('datadir')
+            );
+            $this->logger->debug('Successfully initialized cache using SSP datadir.');
+            return $cache;
+        } catch (\Throwable $exception) {
+            $message = sprintf(
+                'Error initializing job runner cache using datadir. Error was: %s',
+                $exception->getMessage()
+            );
+            $this->logger->debug($message);
+        }
+
+        try {
+            $this->logger->debug('Trying to initialize job runner cache using SSP tempdir.');
+            $cache = new SimpleFileCache(
+                self::CACHE_NAME,
+                $this->sspConfiguration->getPathValue('tempdir')
+            );
+            $this->logger->debug('Successfully initialized job runner cache using SSP tempdir.');
+            return $cache;
+        } catch (\Throwable $exception) {
+            $message = sprintf(
+                'Error initializing job runner cache using tempdir. Error was: %s.',
+                $exception->getMessage()
+            );
+            $this->logger->debug($message);
+        }
+
+        try {
+            $this->logger->debug('Trying to initialize job runner cache using system tmp dir.');
+            $cache = new SimpleFileCache(self::CACHE_NAME);
+            $this->logger->debug('Successfully initialized cache using system tmp dir.');
+            return $cache;
+        } catch (\Throwable $exception) {
+            $message = sprintf(
+                'Error initializing job runner cache. Error was: %s.',
+                $exception->getMessage()
+            );
+            $this->logger->debug($message);
+            throw new Exception($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws Exception
+     */
+    protected function clearCachedState(): void
+    {
+        /** @psalm-suppress InvalidCatch */
+        try {
+            $this->cache->delete(self::CACHE_KEY_STATE);
+        } catch (\Throwable | InvalidArgumentException $exception) {
+            $message = sprintf(
+                'Error clearing job runner cache. Error was: %s.',
+                $exception->getMessage()
+            );
+            $this->logger->error($message);
+            throw new Exception($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws Exception
+     */
+    protected function getCachedState(): ?State
+    {
+        /** @psalm-suppress InvalidCatch */
+        try {
+            /** @var ?State $state */
+            $state = $this->cache->get(self::CACHE_KEY_STATE);
+            if ($state instanceof State) {
+                return $state;
+            } else {
+                return null;
+            }
+        } catch (\Throwable | InvalidArgumentException $exception) {
+            $message = sprintf('Error getting job runner state from cache. Error was: %s', $exception->getMessage());
+            throw new Exception($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws Exception
+     */
+    protected function updateCachedState(State $state, \DateTimeImmutable $updatedAt = null): void
+    {
+        $updatedAt = $updatedAt ?? new \DateTimeImmutable();
+        $state->setUpdatedAt($updatedAt);
+
+        /** @psalm-suppress InvalidCatch */
+        try {
+            $this->cache->set(self::CACHE_KEY_STATE, $state);
+        } catch (\Throwable | InvalidArgumentException $exception) {
+            $message = sprintf('Error setting job runner state. Error was: %s.', $exception->getMessage());
+            $this->logger->error($message);
+            throw new Exception($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws Exception
+     */
+    protected function validateRunConditions(): void
+    {
+        if (
+            $this->moduleConfiguration->getAccountingProcessingType() !==
+            ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS
+        ) {
+            $message = 'Job runner called, however accounting mode is not ' .
+                ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS;
+            $this->logger->warning($message);
+            throw new Exception($message);
+        }
+
+        if ($this->isAnotherJobRunnerActive()) {
+            $message = 'Another job runner is active.';
+            $this->logger->debug($message);
+            throw new Exception($message);
+        }
+    }
+
+    /**
+     * @throws Exception
+     */
+    protected function resolveTrackers(): array
+    {
+        $trackers = [];
+
+        $configuredTrackerClasses = array_merge(
+            [$this->moduleConfiguration->getDefaultDataTrackerAndProviderClass()],
+            $this->moduleConfiguration->getAdditionalTrackers()
+        );
+
+        foreach ($configuredTrackerClasses as $trackerClass) {
+            $trackers[$trackerClass] = $this->authenticationDataTrackerBuilder->build($trackerClass);
+        }
+
+        return $trackers;
+    }
+
+    protected function isCli(): bool
+    {
+        return $this->helpersManager->getEnvironmentHelper()->isCli();
+    }
+
+    /**
+     * Register interrupt handler. This makes it possible to stop job processing gracefully by
+     * clearing the current state. It relies on pcntl extension, so to use this feature,
+     * that extension has to be enabled.
+     * @see https://www.php.net/manual/en/pcntl.installation.php
+     * @return void
+     */
+    protected function registerInterruptHandler(): void
+    {
+        // pcntl won't be available in web server environment, so skip immediately.
+        if (! $this->isCli()) {
+            return;
+        }
+
+        // Extension pcntl doesn't come with PHP by default, so check if the proper function is available.
+        if (! function_exists('pcntl_signal')) {
+            $message = 'pcntl related functions not available, skipping registering interrupt handler.';
+            $this->logger->info($message);
+            $this->state->addStatusMessage($message);
+            return;
+        }
+
+        pcntl_signal(SIGINT, [$this, 'handleInterrupt']);
+        pcntl_signal(SIGTERM, [$this, 'handleInterrupt']);
+    }
+
+    /**
+     * @throws Exception
+     */
+    protected function handleInterrupt(int $signal): void
+    {
+        $message = sprintf('Gracefully stopping job processing. Interrupt signal was %s.', $signal);
+        $this->state->addStatusMessage($message);
+        $this->logger->info($message);
+        $this->state->setIsGracefulInterruptInitiated(true);
+        $this->updateCachedState($this->state);
+    }
+
+    protected function resolveMaximumExecutionTime(): ?\DateInterval
+    {
+        $maximumExecutionTime = $this->moduleConfiguration->getJobRunnerMaximumExecutionTime();
+
+        // If we are in CLI environment, we can safely use module configuration setting.
+        if ($this->isCli()) {
+            return $maximumExecutionTime;
+        }
+
+        // We are in a "web" environment, so take max execution time ini setting into account.
+        $iniMaximumExecutionTimeSeconds = (int)floor((int)ini_get('max_execution_time') * 0.8);
+        $iniMaximumExecutionTime = new \DateInterval('PT' . $iniMaximumExecutionTimeSeconds . 'S');
+
+        // If the module setting is null (meaning infinite), use the ini setting.
+        if ($maximumExecutionTime === null) {
+            return $iniMaximumExecutionTime;
+        }
+
+        // Use the shorter interval from the two...
+        $maximumExecutionTimeSeconds = $this->helpersManager
+            ->getDateTimeHelper()
+            ->convertDateIntervalToSeconds($maximumExecutionTime);
+
+        if ($iniMaximumExecutionTimeSeconds < $maximumExecutionTimeSeconds) {
+            $this->logger->debug('Using maximum execution time from INI setting since it is shorter.');
+            return $iniMaximumExecutionTime;
+        }
+
+        return $maximumExecutionTime;
+    }
+
+    protected function isMaximumExecutionTimeReached(): bool
+    {
+        if ($this->maximumExecutionTime === null) {
+            // Execution time is infinite.
+            return false;
+        }
+
+        $startedAt = $this->state->getStartedAt();
+        if ($startedAt === null) {
+            // Processing has not even started yet.
+            return false;
+        }
+
+        $maxDateTime = $startedAt->add($this->maximumExecutionTime);
+        if ($maxDateTime > (new \DateTimeImmutable())) {
+            // Maximum has not been reached yet.
+            return false;
+        }
+
+        // Maximum has been reached.
+        return true;
+    }
+}
diff --git a/src/Services/JobRunner/RateLimiter.php b/src/Services/JobRunner/RateLimiter.php
new file mode 100644
index 0000000..bc8dc55
--- /dev/null
+++ b/src/Services/JobRunner/RateLimiter.php
@@ -0,0 +1,76 @@
+<?php
+
+namespace SimpleSAML\Module\accounting\Services\JobRunner;
+
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+
+class RateLimiter
+{
+    public const DEFAULT_MAX_PAUSE_DURATION = 'PT10M';
+    public const DEFAULT_MAX_BACKOFF_PAUSE_DURATION = 'PT1M';
+
+    protected HelpersManager $helpersManager;
+
+    protected int $maxPauseInSeconds;
+    protected int $maxBackoffPauseInSeconds;
+    protected int $currentBackoffPauseInSeconds = 1;
+
+    public function __construct(
+        \DateInterval $maxPauseInterval = null,
+        \DateInterval $maxBackoffInterval = null,
+        HelpersManager $helpersManager = null
+    ) {
+        $this->helpersManager = $helpersManager ?? new HelpersManager();
+
+        $this->maxPauseInSeconds = $this->helpersManager->getDateTimeHelper()->convertDateIntervalToSeconds(
+            $maxPauseInterval ?? new \DateInterval(self::DEFAULT_MAX_PAUSE_DURATION)
+        );
+        $this->maxBackoffPauseInSeconds = $this->helpersManager->getDateTimeHelper()->convertDateIntervalToSeconds(
+            $maxBackoffInterval ?? new \DateInterval(self::DEFAULT_MAX_BACKOFF_PAUSE_DURATION)
+        );
+    }
+
+    public function doBackoffPause(): void
+    {
+        /** @psalm-suppress ArgumentTypeCoercion */
+        sleep($this->currentBackoffPauseInSeconds);
+
+        $newBackoffPauseInSeconds = $this->currentBackoffPauseInSeconds + $this->currentBackoffPauseInSeconds;
+        $this->currentBackoffPauseInSeconds = min($newBackoffPauseInSeconds, $this->maxBackoffPauseInSeconds);
+    }
+
+    public function doPause(int $seconds = 1): void
+    {
+        $seconds = $seconds > 0 ? $seconds : 1;
+        sleep($seconds);
+    }
+
+    public function resetBackoffPause(): void
+    {
+        $this->currentBackoffPauseInSeconds = 1;
+    }
+
+    /**
+     * @return int
+     */
+    public function getMaxPauseInSeconds(): int
+    {
+        return $this->maxPauseInSeconds;
+    }
+
+    /**
+     * @return int
+     */
+    public function getMaxBackoffPauseInSeconds(): int
+    {
+        return $this->maxBackoffPauseInSeconds;
+    }
+
+    /**
+     * @return int
+     */
+    public function getCurrentBackoffPauseInSeconds(): int
+    {
+        return $this->currentBackoffPauseInSeconds;
+    }
+}
diff --git a/src/Services/JobRunner/State.php b/src/Services/JobRunner/State.php
new file mode 100644
index 0000000..3d17049
--- /dev/null
+++ b/src/Services/JobRunner/State.php
@@ -0,0 +1,202 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Services\JobRunner;
+
+class State
+{
+    public const MAX_NUMBER_OF_MESSAGES_TO_KEEP = 100;
+    public const DEFAULT_NUMBER_OF_MESSAGES_TO_KEEP = 10;
+
+    protected int $jobRunnerId;
+    protected ?\DateTimeImmutable $startedAt;
+    protected \DateTimeImmutable $updatedAt;
+    protected ?\DateTimeImmutable $endedAt = null;
+    protected int $successfulJobsProcessed = 0;
+    protected int $failedJobsProcessed = 0;
+    /**
+     * @var string[]
+     */
+    protected array $statusMessages = [];
+    protected int $numberOfStatusMessagesToKeep = 10;
+    protected bool $isGracefulInterruptInitiated = false;
+
+    public function __construct(
+        int $jobRunnerId,
+        \DateTimeImmutable $startedAt = null,
+        \DateTimeImmutable $updatedAt = null,
+        int $numberOfStatusMessagesToKeep = self::DEFAULT_NUMBER_OF_MESSAGES_TO_KEEP
+    ) {
+        $this->jobRunnerId = $jobRunnerId;
+        $this->startedAt = $startedAt;
+        $this->updatedAt = $updatedAt ?? new \DateTimeImmutable();
+
+        $this->numberOfStatusMessagesToKeep =
+            $numberOfStatusMessagesToKeep > 0 && $numberOfStatusMessagesToKeep <= self::MAX_NUMBER_OF_MESSAGES_TO_KEEP ?
+            $numberOfStatusMessagesToKeep :
+            self::DEFAULT_NUMBER_OF_MESSAGES_TO_KEEP;
+    }
+
+    /**
+     * @return int
+     */
+    public function getJobRunnerId(): int
+    {
+        return $this->jobRunnerId;
+    }
+
+    /**
+     * @return ?\DateTimeImmutable
+     */
+    public function getStartedAt(): ?\DateTimeImmutable
+    {
+        return $this->startedAt;
+    }
+
+    /**
+     * Set startedAt if not already set.
+     * @param \DateTimeImmutable $startedAt
+     * @return bool True if set, false otherwise.
+     */
+    public function setStartedAt(\DateTimeImmutable $startedAt): bool
+    {
+        if ($this->startedAt === null) {
+            $this->startedAt = $startedAt;
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * @return \DateTimeImmutable
+     */
+    public function getUpdatedAt(): \DateTimeImmutable
+    {
+        return $this->updatedAt;
+    }
+
+    /**
+     * @param \DateTimeImmutable $updatedAt
+     */
+    public function setUpdatedAt(\DateTimeImmutable $updatedAt): void
+    {
+        $this->updatedAt = $updatedAt;
+    }
+
+    /**
+     * Set endedAt if not already set.
+     * @param \DateTimeImmutable $endedAt
+     * @return bool True if set, false otherwise.
+     */
+    public function setEndedAt(\DateTimeImmutable $endedAt): bool
+    {
+        if ($this->endedAt === null) {
+            $this->endedAt = $endedAt;
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * @return ?\DateTimeImmutable
+     */
+    public function getEndedAt(): ?\DateTimeImmutable
+    {
+        return $this->endedAt;
+    }
+
+    public function hasRunStarted(): bool
+    {
+        return $this->startedAt !== null;
+    }
+
+    public function incrementSuccessfulJobsProcessed(): void
+    {
+        $this->successfulJobsProcessed++;
+    }
+
+    public function incrementFailedJobsProcessed(): void
+    {
+        $this->failedJobsProcessed++;
+    }
+
+    /**
+     * @return int
+     */
+    public function getSuccessfulJobsProcessed(): int
+    {
+        return $this->successfulJobsProcessed;
+    }
+
+    /**
+     * @return int
+     */
+    public function getFailedJobsProcessed(): int
+    {
+        return $this->failedJobsProcessed;
+    }
+
+    public function isStale(\DateInterval $threshold): bool
+    {
+        $minDateTime = (new \DateTimeImmutable())->sub($threshold);
+
+        if ($this->getUpdatedAt() < $minDateTime) {
+            return true;
+        }
+
+        return false;
+    }
+
+    public function getTotalJobsProcessed(): int
+    {
+        return $this->getSuccessfulJobsProcessed() + $this->getFailedJobsProcessed();
+    }
+
+    public function addStatusMessage(string $message): void
+    {
+        $this->statusMessages[] = $message;
+
+        if (count($this->statusMessages) > $this->numberOfStatusMessagesToKeep) {
+            array_shift($this->statusMessages);
+        }
+    }
+
+    /**
+     * @return string[]
+     */
+    public function getStatusMessages(): array
+    {
+        return $this->statusMessages;
+    }
+
+    public function getLastStatusMessage(): ?string
+    {
+        if (empty($this->statusMessages)) {
+            return null;
+        }
+
+        $message = end($this->statusMessages);
+        reset($this->statusMessages);
+
+        return $message;
+    }
+
+    /**
+     * @return bool
+     */
+    public function getIsGracefulInterruptInitiated(): bool
+    {
+        return $this->isGracefulInterruptInitiated;
+    }
+
+    /**
+     * @param bool $isGracefulInterruptInitiated
+     */
+    public function setIsGracefulInterruptInitiated(bool $isGracefulInterruptInitiated): void
+    {
+        $this->isGracefulInterruptInitiated = $isGracefulInterruptInitiated;
+    }
+}
diff --git a/src/Services/Logger.php b/src/Services/Logger.php
new file mode 100644
index 0000000..c26c296
--- /dev/null
+++ b/src/Services/Logger.php
@@ -0,0 +1,58 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Services;
+
+use Psr\Log\AbstractLogger;
+use Psr\Log\LogLevel;
+use SimpleSAML\Logger as SspLogger;
+
+class Logger extends AbstractLogger
+{
+    public function log($level, $message, array $context = [], string $prefix = '(accounting) ')
+    {
+        $message = $prefix . $message;
+
+        if (! empty($context)) {
+            $message .= ' Context: ' . var_export($context, true);
+        }
+
+        switch ($level) {
+            case LogLevel::EMERGENCY:
+                SspLogger::emergency($message);
+                break;
+            case LogLevel::CRITICAL:
+                SspLogger::critical($message);
+                break;
+            case LogLevel::ALERT:
+                SspLogger::alert($message);
+                break;
+            case LogLevel::ERROR:
+                SspLogger::error($message);
+                break;
+            case LogLevel::WARNING:
+                SspLogger::warning($message);
+                break;
+            case LogLevel::NOTICE:
+                SspLogger::notice($message);
+                break;
+            case LogLevel::INFO:
+                SspLogger::info($message);
+                break;
+            case LogLevel::DEBUG:
+                SspLogger::debug($message);
+                break;
+        }
+    }
+
+    /**
+     * Log an SSP statistics message.
+     *
+     * @param string $message The message to log.
+     */
+    public function stats(string $message): void
+    {
+        SspLogger::stats($message);
+    }
+}
diff --git a/src/Stores/Bases/AbstractStore.php b/src/Stores/Bases/AbstractStore.php
new file mode 100644
index 0000000..09b5ff6
--- /dev/null
+++ b/src/Stores/Bases/AbstractStore.php
@@ -0,0 +1,64 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Bases;
+
+use Psr\Log\LoggerInterface;
+use ReflectionClass;
+use SimpleSAML\Module\accounting\Interfaces\BuildableUsingModuleConfigurationInterface;
+use SimpleSAML\Module\accounting\Interfaces\SetupableInterface;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+
+abstract class AbstractStore implements BuildableUsingModuleConfigurationInterface, SetupableInterface
+{
+    protected ModuleConfiguration $moduleConfiguration;
+    protected LoggerInterface $logger;
+    protected string $connectionKey;
+
+    /**
+     */
+    public function __construct(
+        ModuleConfiguration $moduleConfiguration,
+        LoggerInterface $logger,
+        string $connectionKey = null,
+        string $connectionType = ModuleConfiguration\ConnectionType::MASTER
+    ) {
+        $this->moduleConfiguration = $moduleConfiguration;
+        $this->logger = $logger;
+
+        $this->connectionKey = $connectionKey ??
+            $moduleConfiguration->getClassConnectionKey($this->getSelfClass(), $connectionType);
+    }
+
+    /**
+     * Get ReflectionClass of current store instance.
+     * @return ReflectionClass
+     */
+    protected function getReflection(): ReflectionClass
+    {
+        return new ReflectionClass($this);
+    }
+
+    /**
+     * Get class of the current store instance.
+     * @return string
+     */
+    protected function getSelfClass(): string
+    {
+        return $this->getReflection()->getName();
+    }
+
+    /**
+     * Build store instance. Must be implemented in child classes for proper return store type.
+     * @param ModuleConfiguration $moduleConfiguration
+     * @param LoggerInterface $logger
+     * @param string|null $connectionKey
+     * @return self
+     */
+    abstract public static function build(
+        ModuleConfiguration $moduleConfiguration,
+        LoggerInterface $logger,
+        string $connectionKey = null
+    ): self;
+}
diff --git a/src/Stores/Bases/DoctrineDbal/AbstractRawEntity.php b/src/Stores/Bases/DoctrineDbal/AbstractRawEntity.php
new file mode 100644
index 0000000..ac0b534
--- /dev/null
+++ b/src/Stores/Bases/DoctrineDbal/AbstractRawEntity.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal;
+
+use DateTimeImmutable;
+use Doctrine\DBAL\Platforms\AbstractPlatform;
+use Doctrine\DBAL\Types\Type;
+use Doctrine\DBAL\Types\Types;
+use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+use Throwable;
+
+abstract class AbstractRawEntity
+{
+    protected array $rawRow;
+    protected AbstractPlatform $abstractPlatform;
+
+    public function __construct(array $rawRow, AbstractPlatform $abstractPlatform)
+    {
+        $this->rawRow = $rawRow;
+        $this->abstractPlatform = $abstractPlatform;
+
+        $this->validate($rawRow);
+    }
+
+    /**
+     * @throws UnexpectedValueException
+     */
+    abstract protected function validate(array $rawRow): void;
+
+    /**
+     * @param mixed $value
+     * @return DateTimeImmutable
+     */
+    protected function resolveDateTimeImmutable($value): DateTimeImmutable
+    {
+        try {
+            /** @var DateTimeImmutable $dateTimeImmutable */
+            $dateTimeImmutable = (Type::getType(Types::DATETIME_IMMUTABLE))
+                ->convertToPHPValue($value, $this->abstractPlatform);
+        } catch (Throwable $exception) {
+            $message = sprintf(
+                'Could not create DateTimeImmutable using value %s. Error was: %s.',
+                var_export($value, true),
+                $exception->getMessage()
+            );
+            throw new UnexpectedValueException($message, (int)$exception->getCode(), $exception);
+        }
+
+        return $dateTimeImmutable;
+    }
+}
diff --git a/src/Stores/Bases/DoctrineDbal/AbstractStore.php b/src/Stores/Bases/DoctrineDbal/AbstractStore.php
new file mode 100644
index 0000000..7dabc98
--- /dev/null
+++ b/src/Stores/Bases/DoctrineDbal/AbstractStore.php
@@ -0,0 +1,118 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal;
+
+use Psr\Log\LoggerInterface;
+use ReflectionClass;
+use SimpleSAML\Module\accounting\Exceptions\StoreException;
+use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Stores\Connections\Bases\AbstractMigrator;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Factory;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator;
+
+abstract class AbstractStore extends \SimpleSAML\Module\accounting\Stores\Bases\AbstractStore
+{
+    protected Connection $connection;
+    protected Migrator $migrator;
+    protected Factory $connectionFactory;
+
+    /**
+     * @throws StoreException
+     */
+    public function __construct(
+        ModuleConfiguration $moduleConfiguration,
+        LoggerInterface $logger,
+        string $connectionKey = null,
+        string $connectionType = ModuleConfiguration\ConnectionType::MASTER,
+        Factory $connectionFactory = null
+    ) {
+        parent::__construct($moduleConfiguration, $logger, $connectionKey, $connectionType);
+
+        $this->connectionFactory = $connectionFactory ?? new Factory($this->moduleConfiguration, $this->logger);
+
+        $this->connection = $this->connectionFactory->buildConnection($this->connectionKey);
+        $this->migrator = $this->connectionFactory->buildMigrator($this->connection);
+    }
+
+    protected function getMigrationsNamespace(): string
+    {
+        return $this->getSelfClass() . '\\' . AbstractMigrator::DEFAULT_MIGRATIONS_DIRECTORY_NAME;
+    }
+
+    protected function areAllMigrationsImplemented(): bool
+    {
+        return !$this->migrator->hasNonImplementedMigrationClasses(
+            $this->getMigrationsDirectory(),
+            $this->getMigrationsNamespace()
+        );
+    }
+
+    /**
+     * @throws StoreException
+     * @throws MigrationException
+     */
+    public function runSetup(): void
+    {
+        if ($this->migrator->needsSetup()) {
+            $this->migrator->runSetup();
+        }
+
+        if (!$this->areAllMigrationsImplemented()) {
+            $this->migrator->runNonImplementedMigrationClasses(
+                $this->getMigrationsDirectory(),
+                $this->getMigrationsNamespace()
+            );
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function needsSetup(): bool
+    {
+        // ... if the migrator itself needs setup.
+        if ($this->migrator->needsSetup()) {
+            return true;
+        }
+
+        // ... if Store migrations need to run
+        if (!$this->areAllMigrationsImplemented()) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Get migrations directory.
+     * By default, it will return {...}/Store/Migrations directory.
+     * @return string
+     */
+    protected function getMigrationsDirectory(): string
+    {
+        $reflection = $this->getReflection();
+        $storeDirName = dirname($reflection->getFileName());
+        $storeShortName = $reflection->getShortName();
+
+        return $storeDirName . DIRECTORY_SEPARATOR .
+            $storeShortName . DIRECTORY_SEPARATOR .
+            AbstractMigrator::DEFAULT_MIGRATIONS_DIRECTORY_NAME;
+    }
+
+    /**
+     * Build store instance. Must be implemented in child classes for proper return store type.
+     * @param ModuleConfiguration $moduleConfiguration
+     * @param LoggerInterface $logger
+     * @param string|null $connectionKey
+     * @return self
+     */
+    abstract public static function build(
+        ModuleConfiguration $moduleConfiguration,
+        LoggerInterface $logger,
+        string $connectionKey = null
+    ): self;
+}
diff --git a/src/Stores/Builders/Bases/AbstractStoreBuilder.php b/src/Stores/Builders/Bases/AbstractStoreBuilder.php
new file mode 100644
index 0000000..5cce33d
--- /dev/null
+++ b/src/Stores/Builders/Bases/AbstractStoreBuilder.php
@@ -0,0 +1,65 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Builders\Bases;
+
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Module\accounting\Exceptions\StoreException;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+use SimpleSAML\Module\accounting\Stores\Interfaces\StoreInterface;
+use Throwable;
+
+use function sprintf;
+use function is_subclass_of;
+
+abstract class AbstractStoreBuilder
+{
+    protected ModuleConfiguration $moduleConfiguration;
+    protected LoggerInterface $logger;
+    protected HelpersManager $helpersManager;
+
+    public function __construct(
+        ModuleConfiguration $moduleConfiguration,
+        LoggerInterface $logger,
+        HelpersManager $helpersManager
+    ) {
+        $this->moduleConfiguration = $moduleConfiguration;
+        $this->logger = $logger;
+        $this->helpersManager = $helpersManager;
+    }
+
+    abstract public function build(
+        string $class,
+        string $connectionKey = null,
+        string $connectionType = ModuleConfiguration\ConnectionType::MASTER
+    ): StoreInterface;
+
+    /**
+     * @throws StoreException
+     */
+    protected function buildGeneric(string $class, array $additionalArguments = []): StoreInterface
+    {
+        try {
+            // Make sure that the class implements StoreInterface
+            if (!is_subclass_of($class, StoreInterface::class)) {
+                throw new StoreException(sprintf('Class %s does not implement StoreInterface.', $class));
+            }
+
+            // Build store...
+            /** @var StoreInterface $store */
+            $store = $this->helpersManager->getInstanceBuilderUsingModuleConfigurationHelper()->build(
+                $class,
+                $this->moduleConfiguration,
+                $this->logger,
+                $additionalArguments
+            );
+        } catch (Throwable $exception) {
+            $message = sprintf('Error building store for class %s. Error was: %s', $class, $exception->getMessage());
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+
+        return $store;
+    }
+}
diff --git a/src/Stores/Builders/DataStoreBuilder.php b/src/Stores/Builders/DataStoreBuilder.php
new file mode 100644
index 0000000..857b447
--- /dev/null
+++ b/src/Stores/Builders/DataStoreBuilder.php
@@ -0,0 +1,32 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Builders;
+
+use SimpleSAML\Module\accounting\Exceptions\StoreException;
+use SimpleSAML\Module\accounting\ModuleConfiguration\ConnectionType;
+use SimpleSAML\Module\accounting\Stores\Interfaces\DataStoreInterface;
+
+class DataStoreBuilder extends Bases\AbstractStoreBuilder
+{
+    /**
+     * @throws StoreException
+     */
+    public function build(
+        string $class,
+        string $connectionKey = null,
+        string $connectionType = ConnectionType::MASTER
+    ): DataStoreInterface {
+        if (!is_subclass_of($class, DataStoreInterface::class)) {
+            throw new StoreException(
+                sprintf('Class \'%s\' does not implement interface \'%s\'.', $class, DataStoreInterface::class)
+            );
+        }
+
+        /** @var DataStoreInterface $store */
+        $store = $this->buildGeneric($class, [$connectionKey, $connectionType]);
+
+        return $store;
+    }
+}
diff --git a/src/Stores/Builders/JobsStoreBuilder.php b/src/Stores/Builders/JobsStoreBuilder.php
new file mode 100644
index 0000000..9ad3784
--- /dev/null
+++ b/src/Stores/Builders/JobsStoreBuilder.php
@@ -0,0 +1,36 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Builders;
+
+use SimpleSAML\Module\accounting\Exceptions\StoreException;
+use SimpleSAML\Module\accounting\ModuleConfiguration\ConnectionType;
+use SimpleSAML\Module\accounting\Stores\Interfaces\JobsStoreInterface;
+
+use function sprintf;
+
+class JobsStoreBuilder extends Bases\AbstractStoreBuilder
+{
+    /**
+     * @throws StoreException
+     */
+    public function build(
+        string $class,
+        string $connectionKey = null,
+        string $connectionType = ConnectionType::MASTER
+    ): JobsStoreInterface {
+        if (!is_subclass_of($class, JobsStoreInterface::class)) {
+            throw new StoreException(
+                sprintf('Class \'%s\' does not implement interface \'%s\'.', $class, JobsStoreInterface::class)
+            );
+        }
+
+        $connectionKey = $connectionKey ?? $this->moduleConfiguration->getClassConnectionKey($class);
+
+        /** @var JobsStoreInterface $store */
+        $store = $this->buildGeneric($class, [$connectionKey, $connectionType]);
+
+        return $store;
+    }
+}
diff --git a/src/Stores/Connections/Bases/AbstractMigrator.php b/src/Stores/Connections/Bases/AbstractMigrator.php
new file mode 100644
index 0000000..2cdb590
--- /dev/null
+++ b/src/Stores/Connections/Bases/AbstractMigrator.php
@@ -0,0 +1,140 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Connections\Bases;
+
+use SimpleSAML\Module\accounting\Exceptions\InvalidValueException;
+use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException;
+use SimpleSAML\Module\accounting\Helpers\FilesystemHelper;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+use SimpleSAML\Module\accounting\Stores\Interfaces\MigrationInterface;
+use Throwable;
+
+abstract class AbstractMigrator
+{
+    public const DEFAULT_MIGRATIONS_DIRECTORY_NAME = 'Migrations';
+
+    protected HelpersManager $helpersManager;
+
+    public function __construct(HelpersManager $helpersManager = null)
+    {
+        $this->helpersManager = $helpersManager ?? new HelpersManager();
+    }
+
+    /**
+     * @param string $directory
+     * @param string $namespace
+     * @return class-string[]
+     */
+    public function gatherMigrationClassesFromDirectory(string $directory, string $namespace): array
+    {
+        $directory = $this->helpersManager->getFilesystemHelper()->getRealPath($directory);
+
+        // Get files without dot directories
+        $files = array_values(array_diff(scandir($directory), ['..', '.']));
+
+        array_walk($files, function (string &$file) use ($namespace) {
+            // Remove .php extension from filename
+            $file = basename($file, '.php');
+            // Prepend namespace for each entry
+            $file = $namespace . '\\' . $file;
+        });
+
+        // Migration classes must follow proper interfaces, so do validate each of them and discard invalid ones.
+        /** @var class-string[] $migrationClasses */
+        $migrationClasses = array_filter($files, function (string $file) {
+            try {
+                $this->validateMigrationClass($file);
+                return true;
+            } catch (InvalidValueException $exception) {
+                return false;
+            }
+        });
+
+        return $migrationClasses;
+    }
+
+    /**
+     * @param class-string[] $migrationClasses
+     * @return void
+     * @throws MigrationException
+     */
+    public function runMigrationClasses(array $migrationClasses): void
+    {
+        foreach ($migrationClasses as $migrationClass) {
+            $this->validateMigrationClass($migrationClass);
+
+            $migration = $this->buildMigrationClassInstance($migrationClass);
+
+            try {
+                $migration->run();
+            } catch (Throwable $exception) {
+                $message = sprintf(
+                    'Could not run migration class %s. Error was: %s',
+                    $migrationClass,
+                    $exception->getMessage()
+                );
+
+                throw new MigrationException($message, (int) $exception->getCode(), $exception);
+            }
+
+            $this->markImplementedMigrationClass($migrationClass);
+        }
+    }
+
+    /**
+     * @return class-string[]
+     */
+    public function getNonImplementedMigrationClasses(string $directory, string $namespace): array
+    {
+        return array_diff(
+            $this->gatherMigrationClassesFromDirectory($directory, $namespace),
+            $this->getImplementedMigrationClasses()
+        );
+    }
+
+    /**
+     * @param string $directory
+     * @param string $namespace
+     * @return bool
+     */
+    public function hasNonImplementedMigrationClasses(string $directory, string $namespace): bool
+    {
+        return ! empty($this->getNonImplementedMigrationClasses($directory, $namespace));
+    }
+
+    /**
+     * @throws MigrationException
+     */
+    public function runNonImplementedMigrationClasses(string $directory, string $namespace): void
+    {
+        $this->runMigrationClasses($this->getNonImplementedMigrationClasses($directory, $namespace));
+    }
+
+    public function validateMigrationClass(string $migrationClass): void
+    {
+        if (! is_subclass_of($migrationClass, MigrationInterface::class)) {
+            throw new InvalidValueException(
+                sprintf('Migration class does not implement MigrationInterface (%s)', $migrationClass)
+            );
+        }
+    }
+
+    /**
+     * @param class-string $migrationClass
+     * @return MigrationInterface
+     */
+    abstract protected function buildMigrationClassInstance(string $migrationClass): MigrationInterface;
+
+    /**
+     * @param class-string $migrationClass
+     * @return void
+     */
+    abstract protected function markImplementedMigrationClass(string $migrationClass): void;
+
+    /**
+     * @return class-string[]
+     */
+    abstract public function getImplementedMigrationClasses(): array;
+}
diff --git a/src/Stores/Connections/DoctrineDbal/Bases/AbstractMigration.php b/src/Stores/Connections/DoctrineDbal/Bases/AbstractMigration.php
new file mode 100644
index 0000000..9619f19
--- /dev/null
+++ b/src/Stores/Connections/DoctrineDbal/Bases/AbstractMigration.php
@@ -0,0 +1,68 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases;
+
+use Doctrine\DBAL\Schema\AbstractSchemaManager;
+use SimpleSAML\Module\accounting\Exceptions\StoreException;
+use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException;
+use SimpleSAML\Module\accounting\Stores\Interfaces\MigrationInterface;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection;
+use Throwable;
+
+abstract class AbstractMigration implements MigrationInterface
+{
+    protected Connection $connection;
+    protected AbstractSchemaManager $schemaManager;
+
+    /**
+     * @throws StoreException
+     */
+    public function __construct(Connection $connection)
+    {
+        $this->connection = $connection;
+        try {
+            $this->schemaManager = $this->connection->dbal()->createSchemaManager();
+        } catch (Throwable $exception) {
+            $message = 'Could not create DBAL schema manager.';
+            throw new StoreException($message, (int) $exception->getCode(), $exception);
+        }
+    }
+
+    protected function prepareGenericMigrationException(
+        string $contextDetails,
+        Throwable $throwable
+    ): MigrationException {
+        $message = sprintf(
+            'There was an error running a migration class %s. Context details: %s. Error was: %s.',
+            static::class,
+            $contextDetails,
+            $throwable->getMessage()
+        );
+
+        return new MigrationException($message, (int) $throwable->getCode(), $throwable);
+    }
+
+    /**
+     * Prepare prefixed table name which will include table prefix from connection, local table prefix, and table name.
+     *
+     * @param string $tableName
+     * @return string
+     */
+    protected function preparePrefixedTableName(string $tableName): string
+    {
+        return $this->connection->preparePrefixedTableName($this->getLocalTablePrefix() . $tableName);
+    }
+
+    /**
+     * Get local table prefix (prefix per migration). Empty string by default. Override in particular migration to
+     * set another local prefix.
+     *
+     * @return string
+     */
+    protected function getLocalTablePrefix(): string
+    {
+        return '';
+    }
+}
diff --git a/src/Stores/Connections/DoctrineDbal/Connection.php b/src/Stores/Connections/DoctrineDbal/Connection.php
new file mode 100644
index 0000000..69c6202
--- /dev/null
+++ b/src/Stores/Connections/DoctrineDbal/Connection.php
@@ -0,0 +1,60 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal;
+
+use Doctrine\DBAL\DriverManager;
+use Doctrine\DBAL\Exception;
+use SimpleSAML\Module\accounting\Exceptions\InvalidConfigurationException;
+use SimpleSAML\Module\accounting\Stores\Interfaces\ConnectionInterface;
+
+class Connection implements ConnectionInterface
+{
+    public const PARAMETER_TABLE_PREFIX = 'table_prefix';
+
+    protected \Doctrine\DBAL\Connection $dbal;
+    protected ?string $tablePrefix;
+
+    public function __construct(array $parameters)
+    {
+        try {
+            /** @psalm-suppress MixedArgumentTypeCoercion */
+            $this->dbal = DriverManager::getConnection($parameters);
+        } catch (Exception $e) {
+            throw new InvalidConfigurationException(
+                'Could not initiate Doctrine DBAL connection with given parameters.'
+            );
+        }
+
+        $this->tablePrefix = $this->getTablePrefixFromParameters($parameters);
+    }
+
+    public function getTablePrefix(): string
+    {
+        return $this->tablePrefix ?? '';
+    }
+
+    public function dbal(): \Doctrine\DBAL\Connection
+    {
+        return $this->dbal;
+    }
+
+    protected function getTablePrefixFromParameters(array $settings): ?string
+    {
+        if (! isset($settings[self::PARAMETER_TABLE_PREFIX])) {
+            return null;
+        }
+
+        if (! is_string($settings[self::PARAMETER_TABLE_PREFIX])) {
+            throw new InvalidConfigurationException('Connection table prefix must be string (if set).');
+        }
+
+        return $settings[self::PARAMETER_TABLE_PREFIX];
+    }
+
+    public function preparePrefixedTableName(string $tableName): string
+    {
+        return $this->getTablePrefix() . $tableName;
+    }
+}
diff --git a/src/Stores/Connections/DoctrineDbal/Factory.php b/src/Stores/Connections/DoctrineDbal/Factory.php
new file mode 100644
index 0000000..b447dbf
--- /dev/null
+++ b/src/Stores/Connections/DoctrineDbal/Factory.php
@@ -0,0 +1,34 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal;
+
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Module\accounting\Exceptions\StoreException;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+
+class Factory
+{
+    protected ModuleConfiguration $moduleConfiguration;
+    protected LoggerInterface $loggerService;
+
+    public function __construct(ModuleConfiguration $moduleConfiguration, LoggerInterface $loggerService)
+    {
+        $this->moduleConfiguration = $moduleConfiguration;
+        $this->loggerService = $loggerService;
+    }
+
+    public function buildConnection(string $connectionKey): Connection
+    {
+        return new Connection($this->moduleConfiguration->getConnectionParameters($connectionKey));
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function buildMigrator(Connection $connection): Migrator
+    {
+        return new Migrator($connection, $this->loggerService);
+    }
+}
diff --git a/src/Stores/Connections/DoctrineDbal/Migrator.php b/src/Stores/Connections/DoctrineDbal/Migrator.php
new file mode 100644
index 0000000..8046446
--- /dev/null
+++ b/src/Stores/Connections/DoctrineDbal/Migrator.php
@@ -0,0 +1,182 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal;
+
+use DateTimeImmutable;
+use Doctrine\DBAL\Schema\AbstractSchemaManager;
+use Doctrine\DBAL\Schema\Table;
+use Doctrine\DBAL\Types\Types;
+use Psr\Log\LoggerInterface;
+use ReflectionClass;
+use ReflectionException;
+use SimpleSAML\Module\accounting\Exceptions\InvalidValueException;
+use SimpleSAML\Module\accounting\Exceptions\StoreException;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+use SimpleSAML\Module\accounting\Stores\Connections\Bases\AbstractMigrator;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration;
+use SimpleSAML\Module\accounting\Stores\Interfaces\MigrationInterface;
+use Throwable;
+
+class Migrator extends AbstractMigrator
+{
+    public const TABLE_NAME = 'migrations';
+
+    public const COLUMN_NAME_ID = 'id';
+    public const COLUMN_NAME_VERSION = 'version';
+    public const COLUMN_NAME_CREATED_AT = 'created_at';
+
+    protected Connection $connection;
+    protected LoggerInterface $logger;
+
+    protected AbstractSchemaManager $schemaManager;
+    protected string $prefixedTableName;
+
+    /**
+     * @throws StoreException
+     */
+    public function __construct(Connection $connection, LoggerInterface $logger, HelpersManager $helpersManager = null)
+    {
+        parent::__construct($helpersManager);
+
+        $this->connection = $connection;
+        $this->logger = $logger;
+
+        try {
+            $this->schemaManager = ($this->connection->dbal())->createSchemaManager();
+        } catch (Throwable $exception) {
+            $message = sprintf('Could not create DBAL schema manager. Error was: %s', $exception->getMessage());
+            throw new StoreException($message, (int) $exception->getCode(), $exception);
+        }
+        $this->prefixedTableName = $this->connection->preparePrefixedTableName(self::TABLE_NAME);
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function needsSetup(): bool
+    {
+        try {
+            return ! $this->schemaManager->tablesExist([$this->prefixedTableName]);
+        } catch (Throwable $exception) {
+            $message = sprintf(
+                'Could not check table \'%s\' existence using schema manager. Error was:%s',
+                $this->prefixedTableName,
+                $exception->getMessage()
+            );
+            throw new StoreException($message, (int) $exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function runSetup(): void
+    {
+        if (! $this->needsSetup()) {
+            $this->logger->warning('Migrator setup has been called, however setup is not needed.');
+            return;
+        }
+
+        $this->createMigrationsTable();
+    }
+
+    /**
+     * @throws StoreException
+     */
+    protected function createMigrationsTable(): void
+    {
+        try {
+            $table = new Table($this->prefixedTableName);
+
+            $table->addColumn(self::COLUMN_NAME_ID, Types::BIGINT)
+                ->setAutoincrement(true)
+                ->setUnsigned(true);
+            $table->addColumn(self::COLUMN_NAME_VERSION, Types::STRING);
+            $table->addColumn(self::COLUMN_NAME_CREATED_AT, Types::DATETIMETZ_IMMUTABLE);
+
+            $table->setPrimaryKey(['id']);
+            $table->addUniqueIndex([self::COLUMN_NAME_VERSION]);
+
+            $this->schemaManager->createTable($table);
+        } catch (Throwable $exception) {
+            $message = sprintf('Error creating migrations table %s.', $this->prefixedTableName);
+            throw new StoreException($message, (int) $exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws ReflectionException
+     */
+    protected function buildMigrationClassInstance(string $migrationClass): MigrationInterface
+    {
+        $this->validateDoctrineDbalMigrationClass($migrationClass);
+
+        /** @var MigrationInterface $migration */
+        $migration = (new ReflectionClass($migrationClass))->newInstance($this->connection);
+
+        return $migration;
+    }
+
+    protected function validateDoctrineDbalMigrationClass(string $migrationClass): void
+    {
+        if (! is_subclass_of($migrationClass, AbstractMigration::class)) {
+            throw new InvalidValueException('Migration class is not Doctrine DBAL migration.');
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    protected function markImplementedMigrationClass(string $migrationClass): void
+    {
+        $queryBuilder = $this->connection->dbal()->createQueryBuilder();
+
+        try {
+            $queryBuilder->insert($this->prefixedTableName)
+                ->values(
+                    [
+                        self::COLUMN_NAME_VERSION => ':' . self::COLUMN_NAME_VERSION,
+                        self::COLUMN_NAME_CREATED_AT => ':' . self::COLUMN_NAME_CREATED_AT,
+                    ]
+                )
+                ->setParameters(
+                    [
+                        self::COLUMN_NAME_VERSION => $migrationClass,
+                        self::COLUMN_NAME_CREATED_AT => new DateTimeImmutable(),
+                    ],
+                    [
+                        self::COLUMN_NAME_VERSION => Types::STRING,
+                        self::COLUMN_NAME_CREATED_AT => Types::DATETIMETZ_IMMUTABLE
+                    ]
+                );
+
+            $queryBuilder->executeStatement();
+        } catch (Throwable $exception) {
+            $message = sprintf('Error marking implemented migrations class %s.', $migrationClass);
+            throw new StoreException($message, (int) $exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function getImplementedMigrationClasses(): array
+    {
+        try {
+            $queryBuilder = $this->connection->dbal()->createQueryBuilder();
+
+            $queryBuilder->select(self::COLUMN_NAME_VERSION)
+                ->from($this->prefixedTableName);
+
+            /** @var class-string[] $migrationClasses */
+            $migrationClasses = $queryBuilder->executeQuery()->fetchFirstColumn();
+        } catch (Throwable $exception) {
+            $message = 'Error getting implemented migration classes.';
+            throw new StoreException($message, (int) $exception->getCode(), $exception);
+        }
+
+        return $migrationClasses;
+    }
+}
diff --git a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store.php b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store.php
new file mode 100644
index 0000000..ce3478f
--- /dev/null
+++ b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store.php
@@ -0,0 +1,557 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned;
+
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Module\accounting\Entities\Activity;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event;
+use SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider;
+use SimpleSAML\Module\accounting\Entities\ServiceProvider;
+use SimpleSAML\Module\accounting\Entities\User;
+use SimpleSAML\Module\accounting\Exceptions\StoreException;
+use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+use SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractStore;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Factory;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\HashDecoratedState;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\RawActivity;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\RawConnectedServiceProvider;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Repository;
+use SimpleSAML\Module\accounting\Stores\Interfaces\DataStoreInterface;
+
+class Store extends AbstractStore implements DataStoreInterface
+{
+    protected Repository $repository;
+    protected HelpersManager $helpersManager;
+
+    /**
+     * @throws StoreException
+     */
+    public function __construct(
+        ModuleConfiguration $moduleConfiguration,
+        LoggerInterface $logger,
+        string $connectionKey = null,
+        string $connectionType = ModuleConfiguration\ConnectionType::MASTER,
+        Factory $connectionFactory = null,
+        Repository $repository = null,
+        HelpersManager $helpersManager = null
+    ) {
+        parent::__construct($moduleConfiguration, $logger, $connectionKey, $connectionType, $connectionFactory);
+
+        $this->repository = $repository ?? new Repository($this->connection, $this->logger);
+        $this->helpersManager = $helpersManager ?? new HelpersManager();
+    }
+
+    /**
+     * Build store instance.
+     * @throws StoreException
+     */
+    public static function build(
+        ModuleConfiguration $moduleConfiguration,
+        LoggerInterface $logger,
+        string $connectionKey = null,
+        string $connectionType = ModuleConfiguration\ConnectionType::MASTER
+    ): self {
+        return new self(
+            $moduleConfiguration,
+            $logger,
+            $connectionKey,
+            $connectionType
+        );
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function persist(Event $authenticationEvent): void
+    {
+        $hashDecoratedState = new HashDecoratedState($authenticationEvent->getState());
+
+        $idpId = $this->resolveIdpId($hashDecoratedState);
+        $idpVersionId = $this->resolveIdpVersionId($idpId, $hashDecoratedState);
+        $spId = $this->resolveSpId($hashDecoratedState);
+        $spVersionId = $this->resolveSpVersionId($spId, $hashDecoratedState);
+        $userId = $this->resolveUserId($hashDecoratedState);
+        $userVersionId = $this->resolveUserVersionId($userId, $hashDecoratedState);
+        $idpSpUserVersionId = $this->resolveIdpSpUserVersionId($idpVersionId, $spVersionId, $userVersionId);
+
+        $this->repository->insertAuthenticationEvent(
+            $idpSpUserVersionId,
+            $authenticationEvent->getHappenedAt(),
+            $authenticationEvent->getState()->getClientIpAddress()
+        );
+    }
+
+    /**
+     * @throws StoreException
+     */
+    protected function resolveIdpId(HashDecoratedState $hashDecoratedState): int
+    {
+        $idpEntityIdHashSha256 = $hashDecoratedState->getIdentityProviderEntityIdHashSha256();
+
+        // Check if it already exists.
+        try {
+            $result = $this->repository->getIdp($idpEntityIdHashSha256);
+            $idpId = $result->fetchOne();
+
+            if ($idpId !== false) {
+                return (int)$idpId;
+            }
+        } catch (\Throwable $exception) {
+            $message = sprintf('Error resolving Idp ID. Error was: %s.', $exception->getMessage());
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+
+        // Create new
+        try {
+            $this->repository->insertIdp(
+                $hashDecoratedState->getState()->getIdentityProviderEntityId(),
+                $idpEntityIdHashSha256
+            );
+        } catch (\Throwable $exception) {
+            $message = sprintf(
+                'Error inserting new IdP, however, continuing in case of race condition. Error was: %s.',
+                $exception->getMessage()
+            );
+            $this->logger->warning($message);
+        }
+
+        // Try again, this time it should exist...
+        try {
+            $result = $this->repository->getIdp($idpEntityIdHashSha256);
+            $idpIdNew = $result->fetchOne();
+
+            if ($idpIdNew !== false) {
+                return (int)$idpIdNew;
+            }
+
+            $message = sprintf(
+                'Error fetching IdP ID even after insertion for entity ID hash SHA256 %s.',
+                $idpEntityIdHashSha256
+            );
+            throw new StoreException($message);
+        } catch (\Throwable $exception) {
+            $message = sprintf('Error resolving Idp ID. Error was: %s.', $exception->getMessage());
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    protected function resolveIdpVersionId(int $idpId, HashDecoratedState $hashDecoratedState): int
+    {
+        // Check if it already exists.
+        $idpMetadataArrayHashSha256 = $hashDecoratedState->getIdentityProviderMetadataArrayHashSha256();
+
+        try {
+            $result = $this->repository->getIdpVersion($idpId, $idpMetadataArrayHashSha256);
+            $idpVersionId = $result->fetchOne();
+
+            if ($idpVersionId !== false) {
+                return (int)$idpVersionId;
+            }
+        } catch (\Throwable $exception) {
+            $message = sprintf('Error resolving IdP Version ID. Error was: %s.', $exception->getMessage());
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+
+        // Create new
+        try {
+            $this->repository->insertIdpVersion(
+                $idpId,
+                serialize($hashDecoratedState->getState()->getIdentityProviderMetadata()),
+                $idpMetadataArrayHashSha256
+            );
+        } catch (\Throwable $exception) {
+            $message = sprintf(
+                'Error inserting new IdP Version, however, continuing in case of race condition. Error was: %s.',
+                $exception->getMessage()
+            );
+            $this->logger->warning($message);
+        }
+
+        // Try again, this time it should exist...
+        try {
+            $result = $this->repository->getIdpVersion($idpId, $idpMetadataArrayHashSha256);
+            $idpVersionIdNew = $result->fetchOne();
+
+            if ($idpVersionIdNew !== false) {
+                return (int)$idpVersionIdNew;
+            }
+
+            $message = sprintf(
+                'Error fetching IdP ID Version even after insertion for Idp ID %s.',
+                $idpId
+            );
+            throw new StoreException($message);
+        } catch (\Throwable $exception) {
+            $message = sprintf('Error resolving Idp Version ID. Error was: %s.', $exception->getMessage());
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    protected function resolveSpId(HashDecoratedState $hashDecoratedState): int
+    {
+        $spEntityIdHashSha256 = $hashDecoratedState->getServiceProviderEntityIdHashSha256();
+
+        // Check if it already exists.
+        try {
+            $result = $this->repository->getSp($spEntityIdHashSha256);
+            $spId = $result->fetchOne();
+
+            if ($spId !== false) {
+                return (int)$spId;
+            }
+        } catch (\Throwable $exception) {
+            $message = sprintf('Error resolving SP ID. Error was: %s.', $exception->getMessage());
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+
+        // Create new
+        try {
+            $this->repository->insertSp(
+                $hashDecoratedState->getState()->getServiceProviderEntityId(),
+                $spEntityIdHashSha256
+            );
+        } catch (\Throwable $exception) {
+            $message = sprintf(
+                'Error inserting new SP, however, continuing in case of race condition. Error was: %s.',
+                $exception->getMessage()
+            );
+            $this->logger->warning($message);
+        }
+
+        // Try again, this time it should exist...
+        try {
+            $result = $this->repository->getSp($spEntityIdHashSha256);
+            $spIdNew = $result->fetchOne();
+
+            if ($spIdNew !== false) {
+                return (int)$spIdNew;
+            }
+
+            $message = sprintf(
+                'Error fetching SP ID even after insertion for entity ID hash SHA256 %s.',
+                $spEntityIdHashSha256
+            );
+            throw new StoreException($message);
+        } catch (\Throwable $exception) {
+            $message = sprintf('Error resolving SP ID. Error was: %s.', $exception->getMessage());
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    protected function resolveSpVersionId(int $spId, HashDecoratedState $hashDecoratedState): int
+    {
+        // Check if it already exists.
+        $spMetadataArrayHashSha256 = $hashDecoratedState->getServiceProviderMetadataArrayHashSha256();
+
+        try {
+            $result = $this->repository->getSpVersion($spId, $spMetadataArrayHashSha256);
+            $spVersionId = $result->fetchOne();
+
+            if ($spVersionId !== false) {
+                return (int)$spVersionId;
+            }
+        } catch (\Throwable $exception) {
+            $message = sprintf('Error resolving SP Version ID. Error was: %s.', $exception->getMessage());
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+
+        // Create new
+        try {
+            $this->repository->insertSpVersion(
+                $spId,
+                serialize($hashDecoratedState->getState()->getServiceProviderMetadata()),
+                $spMetadataArrayHashSha256
+            );
+        } catch (\Throwable $exception) {
+            $message = sprintf(
+                'Error inserting new SP Version, however, continuing in case of race condition. Error was: %s.',
+                $exception->getMessage()
+            );
+            $this->logger->warning($message);
+        }
+
+        // Try again, this time it should exist...
+        try {
+            $result = $this->repository->getSpVersion($spId, $spMetadataArrayHashSha256);
+            $spVersionIdNew = $result->fetchOne();
+
+            if ($spVersionIdNew !== false) {
+                return (int)$spVersionIdNew;
+            }
+
+            $message = sprintf(
+                'Error fetching SP Version even after insertion for SP ID %s.',
+                $spId
+            );
+            throw new StoreException($message);
+        } catch (\Throwable $exception) {
+            $message = sprintf('Error resolving SP Version ID. Error was: %s.', $exception->getMessage());
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    protected function resolveUserId(HashDecoratedState $hashDecoratedState): int
+    {
+        $userIdentifierAttributeName = $this->moduleConfiguration->getUserIdAttributeName();
+
+        $userIdentifierValue = $hashDecoratedState->getState()->getAttributeValue($userIdentifierAttributeName);
+        if ($userIdentifierValue === null) {
+            $message = sprintf('Attributes do not contain user ID attribute %s.', $userIdentifierAttributeName);
+            throw new UnexpectedValueException($message);
+        }
+
+        $userIdentifierValueHashSha256 = $this->helpersManager->getHashHelper()->getSha256($userIdentifierValue);
+
+        // Check if it already exists.
+        try {
+            $result = $this->repository->getUser($userIdentifierValueHashSha256);
+            $userId = $result->fetchOne();
+
+            if ($userId !== false) {
+                return (int)$userId;
+            }
+        } catch (\Throwable $exception) {
+            $message = sprintf('Error resolving user ID. Error was: %s.', $exception->getMessage());
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+
+        // Create new
+        try {
+            $this->repository->insertUser($userIdentifierValue, $userIdentifierValueHashSha256);
+        } catch (\Throwable $exception) {
+            $message = sprintf(
+                'Error inserting new user, however, continuing in case of race condition. Error was: %s.',
+                $exception->getMessage()
+            );
+            $this->logger->warning($message);
+        }
+
+        // Try again, this time it should exist...
+        try {
+            $result = $this->repository->getUser($userIdentifierValueHashSha256);
+            $userIdNew = $result->fetchOne();
+
+            if ($userIdNew !== false) {
+                return (int)$userIdNew;
+            }
+
+            $message = sprintf(
+                'Error fetching user even after insertion for identifier value hash SHA256 %s.',
+                $userIdentifierValueHashSha256
+            );
+            throw new StoreException($message);
+        } catch (\Throwable $exception) {
+            $message = sprintf('Error resolving user ID. Error was: %s.', $exception->getMessage());
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    protected function resolveUserVersionId(int $userId, HashDecoratedState $hashDecoratedState): int
+    {
+        $attributeArrayHashSha256 = $hashDecoratedState->getAttributesArrayHashSha256();
+
+        // Check if it already exists.
+        try {
+            $result = $this->repository->getUserVersion($userId, $attributeArrayHashSha256);
+            $userVersionId = $result->fetchOne();
+
+            if ($userVersionId !== false) {
+                return (int)$userVersionId;
+            }
+        } catch (\Throwable $exception) {
+            $message = sprintf('Error resolving user version ID. Error was: %s.', $exception->getMessage());
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+
+        // Create new
+        try {
+            $this->repository->insertUserVersion(
+                $userId,
+                serialize($hashDecoratedState->getState()->getAttributes()),
+                $attributeArrayHashSha256
+            );
+        } catch (\Throwable $exception) {
+            $message = sprintf(
+                'Error inserting new user version, however, continuing in case of race condition. Error was: %s.',
+                $exception->getMessage()
+            );
+            $this->logger->warning($message);
+        }
+
+        // Try again, this time it should exist...
+        try {
+            $result = $this->repository->getUserVersion($userId, $attributeArrayHashSha256);
+            $userVersionIdNew = $result->fetchOne();
+
+            if ($userVersionIdNew !== false) {
+                return (int)$userVersionIdNew;
+            }
+
+            $message = sprintf(
+                'Error fetching user version even after insertion for user ID %s.',
+                $userId
+            );
+            throw new StoreException($message);
+        } catch (\Throwable $exception) {
+            $message = sprintf('Error resolving user version ID. Error was: %s.', $exception->getMessage());
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    protected function resolveIdpSpUserVersionId(int $idpVersionId, int $spVersionId, int $userVersionId): int
+    {
+        // Check if it already exists.
+        try {
+            $result = $this->repository->getIdpSpUserVersion($idpVersionId, $spVersionId, $userVersionId);
+            $IdpSpUserVersionId = $result->fetchOne();
+
+            if ($IdpSpUserVersionId !== false) {
+                return (int)$IdpSpUserVersionId;
+            }
+        } catch (\Throwable $exception) {
+            $message = sprintf('Error resolving IdpSpUserVersion ID. Error was: %s.', $exception->getMessage());
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+
+        // Create new
+        try {
+            $this->repository->insertIdpSpUserVersion($idpVersionId, $spVersionId, $userVersionId);
+        } catch (\Throwable $exception) {
+            $message = sprintf(
+                'Error inserting new IdpSpUserVersion, however, continuing in case of race condition. ' .
+                'Error was: %s.',
+                $exception->getMessage()
+            );
+            $this->logger->warning($message);
+        }
+
+        // Try again, this time it should exist...
+        try {
+            $result = $this->repository->getIdpSpUserVersion($idpVersionId, $spVersionId, $userVersionId);
+            $IdpSpUserVersionIdNew = $result->fetchOne();
+
+            if ($IdpSpUserVersionIdNew !== false) {
+                return (int)$IdpSpUserVersionIdNew;
+            }
+
+            $message = sprintf(
+                'Error fetching IdpSpUserVersion ID even after insertion for IdpVersion %s, SpVersion ID %s and ' .
+                'UserVersion ID %s.',
+                $idpVersionId,
+                $spVersionId,
+                $userVersionId
+            );
+            throw new StoreException($message);
+        } catch (\Throwable $exception) {
+            $message = sprintf('Error resolving IdpSpUserVersion ID. Error was: %s.', $exception->getMessage());
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function getConnectedOrganizations(string $userIdentifierHashSha256): ConnectedServiceProvider\Bag
+    {
+        $connectedServiceProviderBag = new ConnectedServiceProvider\Bag();
+
+        $results = $this->repository->getConnectedServiceProviders($userIdentifierHashSha256);
+
+        if (empty($results)) {
+            return $connectedServiceProviderBag;
+        }
+
+        try {
+            $databasePlatform = $this->connection->dbal()->getDatabasePlatform();
+
+            /** @var array $result */
+            foreach ($results as $result) {
+                $rawConnectedServiceProvider = new RawConnectedServiceProvider($result, $databasePlatform);
+
+                $serviceProvider = new ServiceProvider($rawConnectedServiceProvider->getServiceProviderMetadata());
+                $user = new User($rawConnectedServiceProvider->getUserAttributes());
+
+                $connectedServiceProviderBag->addOrReplace(
+                    new ConnectedServiceProvider(
+                        $serviceProvider,
+                        $rawConnectedServiceProvider->getNumberOfAuthentications(),
+                        $rawConnectedServiceProvider->getLastAuthenticationAt(),
+                        $rawConnectedServiceProvider->getFirstAuthenticationAt(),
+                        $user
+                    )
+                );
+            }
+        } catch (\Throwable $exception) {
+            $message = sprintf(
+                'Error populating connected service provider bag. Error was: %s',
+                $exception->getMessage()
+            );
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+
+        return $connectedServiceProviderBag;
+    }
+
+
+    /**
+     * @throws StoreException
+     */
+    public function getActivity(string $userIdentifierHashSha256, int $maxResults, int $firstResult): Activity\Bag
+    {
+        $results =  $this->repository->getActivity($userIdentifierHashSha256, $maxResults, $firstResult);
+
+        $activityBag = new Activity\Bag();
+
+        if (empty($results)) {
+            return $activityBag;
+        }
+
+        try {
+            /** @var array $result */
+            foreach ($results as $result) {
+                $rawActivity = new RawActivity($result, $this->connection->dbal()->getDatabasePlatform());
+                $serviceProvider = new ServiceProvider($rawActivity->getServiceProviderMetadata());
+                $user = new User($rawActivity->getUserAttributes());
+
+                $activityBag->add(
+                    new Activity(
+                        $serviceProvider,
+                        $user,
+                        $rawActivity->getHappenedAt(),
+                        $rawActivity->getClientIpAddress()
+                    )
+                );
+            }
+        } catch (\Throwable $exception) {
+            $message = sprintf(
+                'Error populating activity bag. Error was: %s',
+                $exception->getMessage()
+            );
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+
+        return $activityBag;
+    }
+
+    public function deleteDataOlderThan(\DateTimeImmutable $dateTime): void
+    {
+        // Only delete authentication events. Versioned data (IdP / SP metadata, user attributes) remain.
+        $this->repository->deleteAuthenticationEventsOlderThan($dateTime);
+    }
+}
diff --git a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/HashDecoratedState.php b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/HashDecoratedState.php
new file mode 100644
index 0000000..6811a67
--- /dev/null
+++ b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/HashDecoratedState.php
@@ -0,0 +1,84 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store;
+
+use SimpleSAML\Module\accounting\Entities\Authentication\State;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+
+class HashDecoratedState
+{
+    protected State $state;
+    protected HelpersManager $helpersManager;
+
+    protected string $identityProviderEntityIdHashSha256;
+    protected string $serviceProviderEntityIdHashSha256;
+    protected string $identityProviderMetadataArrayHashSha256;
+    protected string $serviceProviderMetadataArrayHashSha256;
+    protected string $attributesArrayHashSha256;
+
+    public function __construct(State $state, HelpersManager $helpersManager = null)
+    {
+        $this->state = $state;
+        $this->helpersManager = $helpersManager ?? new HelpersManager();
+
+        $this->identityProviderEntityIdHashSha256 = $this->helpersManager->getHashHelper()
+            ->getSha256($state->getIdentityProviderEntityId());
+        $this->identityProviderMetadataArrayHashSha256 = $this->helpersManager->getHashHelper()
+            ->getSha256ForArray($state->getIdentityProviderMetadata());
+
+        $this->serviceProviderEntityIdHashSha256 = $this->helpersManager->getHashHelper()
+            ->getSha256($state->getServiceProviderEntityId());
+        $this->serviceProviderMetadataArrayHashSha256 = $this->helpersManager->getHashHelper()
+            ->getSha256ForArray($state->getServiceProviderMetadata());
+
+        $this->attributesArrayHashSha256 = $this->helpersManager->getHashHelper()
+            ->getSha256ForArray($state->getAttributes());
+    }
+
+    /**
+     * @return State
+     */
+    public function getState(): State
+    {
+        return $this->state;
+    }
+
+    /**
+     * @return string
+     */
+    public function getIdentityProviderEntityIdHashSha256(): string
+    {
+        return $this->identityProviderEntityIdHashSha256;
+    }
+
+    /**
+     * @return string
+     */
+    public function getServiceProviderEntityIdHashSha256(): string
+    {
+        return $this->serviceProviderEntityIdHashSha256;
+    }
+
+    /**
+     * @return string
+     */
+    public function getIdentityProviderMetadataArrayHashSha256(): string
+    {
+        return $this->identityProviderMetadataArrayHashSha256;
+    }
+
+    public function getServiceProviderMetadataArrayHashSha256(): string
+    {
+        return $this->serviceProviderMetadataArrayHashSha256;
+    }
+
+    /**
+     * @return string
+     */
+    public function getAttributesArrayHashSha256(): string
+    {
+        return $this->attributesArrayHashSha256;
+    }
+}
diff --git a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000000CreateIdpTable.php b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000000CreateIdpTable.php
new file mode 100644
index 0000000..66d8b08
--- /dev/null
+++ b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000000CreateIdpTable.php
@@ -0,0 +1,69 @@
+<?php
+
+namespace SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations;
+
+use Doctrine\DBAL\Schema\Table;
+use Doctrine\DBAL\Types\Types;
+use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\TableConstants;
+
+class Version20220801000000CreateIdpTable extends AbstractMigration
+{
+    protected function getLocalTablePrefix(): string
+    {
+        return 'vds_';
+    }
+
+    /**
+     * @inheritDoc
+     * @throws MigrationException
+     */
+    public function run(): void
+    {
+        $tableName = $this->preparePrefixedTableName('idp');
+
+        try {
+            $table = new Table($tableName);
+
+            $table->addColumn('id', Types::BIGINT)
+                ->setUnsigned(true)
+                ->setAutoincrement(true);
+
+            $table->addColumn('entity_id', Types::STRING)
+                ->setLength(TableConstants::COLUMN_ENTITY_ID_LENGTH);
+
+            $table->addColumn('entity_id_hash_sha256', Types::STRING)
+                ->setLength(TableConstants::COLUMN_HASH_SHA265_HEXITS_LENGTH)
+                ->setFixed(true);
+
+            $table->addColumn('created_at', Types::DATETIMETZ_IMMUTABLE);
+
+            $table->setPrimaryKey(['id']);
+
+            $table->addUniqueConstraint(['entity_id_hash_sha256']);
+
+            $this->schemaManager->createTable($table);
+        } catch (\Throwable $exception) {
+            throw $this->prepareGenericMigrationException(
+                \sprintf('Error creating table \'%s.', $tableName),
+                $exception
+            );
+        }
+    }
+
+    /**
+     * @inheritDoc
+     * @throws MigrationException
+     */
+    public function revert(): void
+    {
+        $tableName = $this->preparePrefixedTableName('idp');
+
+        try {
+            $this->schemaManager->dropTable($tableName);
+        } catch (\Throwable $exception) {
+            throw $this->prepareGenericMigrationException(\sprintf('Could not drop table %s.', $tableName), $exception);
+        }
+    }
+}
diff --git a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000100CreateIdpVersionTable.php b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000100CreateIdpVersionTable.php
new file mode 100644
index 0000000..4c18cf2
--- /dev/null
+++ b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000100CreateIdpVersionTable.php
@@ -0,0 +1,74 @@
+<?php
+
+namespace SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations;
+
+use Doctrine\DBAL\Schema\Table;
+use Doctrine\DBAL\Schema\TableDiff;
+use Doctrine\DBAL\Types\Types;
+use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\TableConstants;
+
+class Version20220801000100CreateIdpVersionTable extends AbstractMigration
+{
+    protected function getLocalTablePrefix(): string
+    {
+        return 'vds_';
+    }
+
+    /**
+     * @inheritDoc
+     * @throws MigrationException
+     */
+    public function run(): void
+    {
+        $tableName = $this->preparePrefixedTableName('idp_version');
+
+        try {
+            $table = new Table($tableName);
+
+            $table->addColumn('id', Types::BIGINT)
+                ->setUnsigned(true)
+                ->setAutoincrement(true);
+
+            $table->addColumn('idp_id', Types::BIGINT)
+                ->setUnsigned(true);
+
+            $table->addColumn('metadata', Types::TEXT);
+
+            $table->addColumn('metadata_hash_sha256', Types::STRING)
+                ->setLength(TableConstants::COLUMN_HASH_SHA265_HEXITS_LENGTH)
+                ->setFixed(true);
+
+            $table->addColumn('created_at', Types::DATETIMETZ_IMMUTABLE);
+
+            $table->setPrimaryKey(['id']);
+
+            $table->addForeignKeyConstraint($this->preparePrefixedTableName('idp'), ['idp_id'], ['id']);
+
+            $table->addUniqueConstraint(['metadata_hash_sha256']);
+
+            $this->schemaManager->createTable($table);
+        } catch (\Throwable $exception) {
+            throw $this->prepareGenericMigrationException(
+                \sprintf('Error creating table \'%s.', $tableName),
+                $exception
+            );
+        }
+    }
+
+    /**
+     * @inheritDoc
+     * @throws MigrationException
+     */
+    public function revert(): void
+    {
+        $tableName = $this->preparePrefixedTableName('idp_version');
+
+        try {
+            $this->schemaManager->dropTable($tableName);
+        } catch (\Throwable $exception) {
+            throw $this->prepareGenericMigrationException(\sprintf('Could not drop table %s.', $tableName), $exception);
+        }
+    }
+}
diff --git a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000200CreateSpTable.php b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000200CreateSpTable.php
new file mode 100644
index 0000000..b9418b6
--- /dev/null
+++ b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000200CreateSpTable.php
@@ -0,0 +1,69 @@
+<?php
+
+namespace SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations;
+
+use Doctrine\DBAL\Schema\Table;
+use Doctrine\DBAL\Types\Types;
+use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\TableConstants;
+
+class Version20220801000200CreateSpTable extends AbstractMigration
+{
+    protected function getLocalTablePrefix(): string
+    {
+        return 'vds_';
+    }
+
+    /**
+     * @inheritDoc
+     * @throws MigrationException
+     */
+    public function run(): void
+    {
+        $tableName = $this->preparePrefixedTableName('sp');
+
+        try {
+            $table = new Table($tableName);
+
+            $table->addColumn('id', Types::BIGINT)
+                ->setUnsigned(true)
+                ->setAutoincrement(true);
+
+            $table->addColumn('entity_id', Types::STRING)
+                ->setLength(TableConstants::COLUMN_ENTITY_ID_LENGTH);
+
+            $table->addColumn('entity_id_hash_sha256', Types::STRING)
+                ->setLength(TableConstants::COLUMN_HASH_SHA265_HEXITS_LENGTH)
+                ->setFixed(true);
+
+            $table->addColumn('created_at', Types::DATETIMETZ_IMMUTABLE);
+
+            $table->setPrimaryKey(['id']);
+
+            $table->addUniqueConstraint(['entity_id_hash_sha256']);
+
+            $this->schemaManager->createTable($table);
+        } catch (\Throwable $exception) {
+            throw $this->prepareGenericMigrationException(
+                \sprintf('Error creating table \'%s.', $tableName),
+                $exception
+            );
+        }
+    }
+
+    /**
+     * @inheritDoc
+     * @throws MigrationException
+     */
+    public function revert(): void
+    {
+        $tableName = $this->preparePrefixedTableName('sp');
+
+        try {
+            $this->schemaManager->dropTable($tableName);
+        } catch (\Throwable $exception) {
+            throw $this->prepareGenericMigrationException(\sprintf('Could not drop table %s.', $tableName), $exception);
+        }
+    }
+}
diff --git a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000300CreateSpVersionTable.php b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000300CreateSpVersionTable.php
new file mode 100644
index 0000000..13a5535
--- /dev/null
+++ b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000300CreateSpVersionTable.php
@@ -0,0 +1,74 @@
+<?php
+
+namespace SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations;
+
+use Doctrine\DBAL\Schema\Table;
+use Doctrine\DBAL\Schema\TableDiff;
+use Doctrine\DBAL\Types\Types;
+use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\TableConstants;
+
+class Version20220801000300CreateSpVersionTable extends AbstractMigration
+{
+    protected function getLocalTablePrefix(): string
+    {
+        return 'vds_';
+    }
+
+    /**
+     * @inheritDoc
+     * @throws MigrationException
+     */
+    public function run(): void
+    {
+        $tableName = $this->preparePrefixedTableName('sp_version');
+
+        try {
+            $table = new Table($tableName);
+
+            $table->addColumn('id', Types::BIGINT)
+                ->setUnsigned(true)
+                ->setAutoincrement(true);
+
+            $table->addColumn('sp_id', Types::BIGINT)
+                ->setUnsigned(true);
+
+            $table->addColumn('metadata', Types::TEXT);
+
+            $table->addColumn('metadata_hash_sha256', Types::STRING)
+                ->setLength(TableConstants::COLUMN_HASH_SHA265_HEXITS_LENGTH)
+                ->setFixed(true);
+
+            $table->addColumn('created_at', Types::DATETIMETZ_IMMUTABLE);
+
+            $table->setPrimaryKey(['id']);
+
+            $table->addForeignKeyConstraint($this->preparePrefixedTableName('sp'), ['sp_id'], ['id']);
+
+            $table->addUniqueConstraint(['metadata_hash_sha256']);
+
+            $this->schemaManager->createTable($table);
+        } catch (\Throwable $exception) {
+            throw $this->prepareGenericMigrationException(
+                \sprintf('Error creating table \'%s.', $tableName),
+                $exception
+            );
+        }
+    }
+
+    /**
+     * @inheritDoc
+     * @throws MigrationException
+     */
+    public function revert(): void
+    {
+        $tableName = $this->preparePrefixedTableName('sp_version');
+
+        try {
+            $this->schemaManager->dropTable($tableName);
+        } catch (\Throwable $exception) {
+            throw $this->prepareGenericMigrationException(\sprintf('Could not drop table %s.', $tableName), $exception);
+        }
+    }
+}
diff --git a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000400CreateUserTable.php b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000400CreateUserTable.php
new file mode 100644
index 0000000..667d8ff
--- /dev/null
+++ b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000400CreateUserTable.php
@@ -0,0 +1,70 @@
+<?php
+
+namespace SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations;
+
+use Doctrine\DBAL\Schema\Table;
+use Doctrine\DBAL\Schema\TableDiff;
+use Doctrine\DBAL\Types\Types;
+use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\TableConstants;
+
+class Version20220801000400CreateUserTable extends AbstractMigration
+{
+    protected function getLocalTablePrefix(): string
+    {
+        return 'vds_';
+    }
+
+    /**
+     * @inheritDoc
+     * @throws MigrationException
+     */
+    public function run(): void
+    {
+        $tableName = $this->preparePrefixedTableName('user');
+
+        try {
+            $table = new Table($tableName);
+
+            $table->addColumn('id', Types::BIGINT)
+                ->setUnsigned(true)
+                ->setAutoincrement(true);
+
+            $table->addColumn('identifier', Types::TEXT)
+                ->setLength(65535);
+
+            $table->addColumn('identifier_hash_sha256', Types::STRING)
+                ->setLength(TableConstants::COLUMN_HASH_SHA265_HEXITS_LENGTH)
+                ->setFixed(true);
+
+            $table->addColumn('created_at', Types::DATETIMETZ_IMMUTABLE);
+
+            $table->setPrimaryKey(['id']);
+
+            $table->addUniqueConstraint(['identifier_hash_sha256']);
+
+            $this->schemaManager->createTable($table);
+        } catch (\Throwable $exception) {
+            throw $this->prepareGenericMigrationException(
+                \sprintf('Error creating table \'%s.', $tableName),
+                $exception
+            );
+        }
+    }
+
+    /**
+     * @inheritDoc
+     * @throws MigrationException
+     */
+    public function revert(): void
+    {
+        $tableName = $this->preparePrefixedTableName('user');
+
+        try {
+            $this->schemaManager->dropTable($tableName);
+        } catch (\Throwable $exception) {
+            throw $this->prepareGenericMigrationException(\sprintf('Could not drop table %s.', $tableName), $exception);
+        }
+    }
+}
diff --git a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000500CreateUserVersionTable.php b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000500CreateUserVersionTable.php
new file mode 100644
index 0000000..fcb2b42
--- /dev/null
+++ b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000500CreateUserVersionTable.php
@@ -0,0 +1,75 @@
+<?php
+
+namespace SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations;
+
+use Doctrine\DBAL\Schema\Table;
+use Doctrine\DBAL\Schema\TableDiff;
+use Doctrine\DBAL\Types\Types;
+use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\TableConstants;
+
+class Version20220801000500CreateUserVersionTable extends AbstractMigration
+{
+    protected function getLocalTablePrefix(): string
+    {
+        return 'vds_';
+    }
+
+    /**
+     * @inheritDoc
+     * @throws MigrationException
+     */
+    public function run(): void
+    {
+        $tableName = $this->preparePrefixedTableName('user_version');
+
+        try {
+            $table = new Table($tableName);
+
+            $table->addColumn('id', Types::BIGINT)
+                ->setUnsigned(true)
+                ->setAutoincrement(true);
+
+            $table->addColumn('user_id', Types::BIGINT)
+                ->setUnsigned(true);
+
+            $table->addColumn('attributes', Types::TEXT)
+                ->setComment('Serialized attributes.');
+
+            $table->addColumn('attributes_hash_sha256', Types::STRING)
+                ->setLength(TableConstants::COLUMN_HASH_SHA265_HEXITS_LENGTH)
+                ->setFixed(true);
+
+            $table->addColumn('created_at', Types::DATETIMETZ_IMMUTABLE);
+
+            $table->setPrimaryKey(['id']);
+
+            $table->addForeignKeyConstraint($this->preparePrefixedTableName('user'), ['user_id'], ['id']);
+
+            $table->addUniqueConstraint(['attributes_hash_sha256']);
+
+            $this->schemaManager->createTable($table);
+        } catch (\Throwable $exception) {
+            throw $this->prepareGenericMigrationException(
+                \sprintf('Error creating table \'%s.', $tableName),
+                $exception
+            );
+        }
+    }
+
+    /**
+     * @inheritDoc
+     * @throws MigrationException
+     */
+    public function revert(): void
+    {
+        $tableName = $this->preparePrefixedTableName('user_version');
+
+        try {
+            $this->schemaManager->dropTable($tableName);
+        } catch (\Throwable $exception) {
+            throw $this->prepareGenericMigrationException(\sprintf('Could not drop table %s.', $tableName), $exception);
+        }
+    }
+}
diff --git a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000600CreateIdpSpUserVersionTable.php b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000600CreateIdpSpUserVersionTable.php
new file mode 100644
index 0000000..625e651
--- /dev/null
+++ b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000600CreateIdpSpUserVersionTable.php
@@ -0,0 +1,92 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations;
+
+use Doctrine\DBAL\Schema\Table;
+use Doctrine\DBAL\Schema\TableDiff;
+use Doctrine\DBAL\Types\Types;
+use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\TableConstants;
+
+class Version20220801000600CreateIdpSpUserVersionTable extends AbstractMigration
+{
+    protected function getLocalTablePrefix(): string
+    {
+        return 'vds_';
+    }
+
+    /**
+     * @inheritDoc
+     * @throws MigrationException
+     */
+    public function run(): void
+    {
+        $tableName = $this->preparePrefixedTableName('idp_sp_user_version');
+
+        try {
+            $table = new Table($tableName);
+
+            $table->addColumn('id', Types::BIGINT)
+                ->setUnsigned(true)
+                ->setAutoincrement(true);
+
+            $table->addColumn('idp_version_id', Types::BIGINT)
+                ->setUnsigned(true);
+
+            $table->addColumn('sp_version_id', Types::BIGINT)
+                ->setUnsigned(true);
+
+            $table->addColumn('user_version_id', Types::BIGINT)
+                ->setUnsigned(true);
+
+            $table->addColumn('created_at', Types::DATETIMETZ_IMMUTABLE);
+
+            $table->setPrimaryKey(['id']);
+
+            $table->addForeignKeyConstraint(
+                $this->preparePrefixedTableName('idp_version'),
+                ['idp_version_id'],
+                ['id']
+            );
+
+            $table->addForeignKeyConstraint(
+                $this->preparePrefixedTableName('sp_version'),
+                ['sp_version_id'],
+                ['id']
+            );
+
+            $table->addForeignKeyConstraint(
+                $this->preparePrefixedTableName('user_version'),
+                ['user_version_id'],
+                ['id']
+            );
+
+            $table->addUniqueConstraint(['idp_version_id', 'sp_version_id', 'user_version_id']);
+
+            $this->schemaManager->createTable($table);
+        } catch (\Throwable $exception) {
+            throw $this->prepareGenericMigrationException(
+                \sprintf('Error creating table \'%s.', $tableName),
+                $exception
+            );
+        }
+    }
+
+    /**
+     * @inheritDoc
+     * @throws MigrationException
+     */
+    public function revert(): void
+    {
+        $tableName = $this->preparePrefixedTableName('idp_sp_user_version');
+
+        try {
+            $this->schemaManager->dropTable($tableName);
+        } catch (\Throwable $exception) {
+            throw $this->prepareGenericMigrationException(\sprintf('Could not drop table %s.', $tableName), $exception);
+        }
+    }
+}
diff --git a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000700CreateAuthenticationEventTable.php b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000700CreateAuthenticationEventTable.php
new file mode 100644
index 0000000..be8e304
--- /dev/null
+++ b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000700CreateAuthenticationEventTable.php
@@ -0,0 +1,79 @@
+<?php
+
+namespace SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations;
+
+use Doctrine\DBAL\Schema\Table;
+use Doctrine\DBAL\Schema\TableDiff;
+use Doctrine\DBAL\Types\Types;
+use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\TableConstants;
+
+class Version20220801000700CreateAuthenticationEventTable extends AbstractMigration
+{
+    protected function getLocalTablePrefix(): string
+    {
+        return 'vds_';
+    }
+
+    /**
+     * @inheritDoc
+     * @throws MigrationException
+     */
+    public function run(): void
+    {
+        $tableName = $this->preparePrefixedTableName('authentication_event');
+
+        try {
+            $table = new Table($tableName);
+
+            $table->addColumn('id', Types::BIGINT)
+                ->setUnsigned(true)
+                ->setAutoincrement(true);
+
+            $table->addColumn('idp_sp_user_version_id', Types::BIGINT)
+                ->setUnsigned(true);
+
+            $table->addColumn('happened_at', Types::DATETIMETZ_IMMUTABLE);
+
+            $table->addColumn('client_ip_address', Types::STRING)
+                ->setLength(TableConstants::COLUMN_IP_ADDRESS_LENGTH)
+                ->setNotnull(false);
+
+            $table->addColumn('created_at', Types::DATETIMETZ_IMMUTABLE);
+
+            $table->setPrimaryKey(['id']);
+
+            $table->addForeignKeyConstraint(
+                $this->preparePrefixedTableName('idp_sp_user_version'),
+                ['idp_sp_user_version_id'],
+                ['id']
+            );
+
+            // Old data can be deleted using happened_at column, so add index for it.
+            $table->addIndex(['happened_at']);
+
+            $this->schemaManager->createTable($table);
+        } catch (\Throwable $exception) {
+            throw $this->prepareGenericMigrationException(
+                \sprintf('Error creating table \'%s.', $tableName),
+                $exception
+            );
+        }
+    }
+
+    /**
+     * @inheritDoc
+     * @throws MigrationException
+     */
+    public function revert(): void
+    {
+        $tableName = $this->preparePrefixedTableName('authentication_event');
+
+        try {
+            $this->schemaManager->dropTable($tableName);
+        } catch (\Throwable $exception) {
+            throw $this->prepareGenericMigrationException(\sprintf('Could not drop table %s.', $tableName), $exception);
+        }
+    }
+}
diff --git a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawActivity.php b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawActivity.php
new file mode 100644
index 0000000..17fb9e3
--- /dev/null
+++ b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawActivity.php
@@ -0,0 +1,139 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store;
+
+use DateTimeImmutable;
+use Doctrine\DBAL\Platforms\AbstractPlatform;
+use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+use SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractRawEntity;
+
+class RawActivity extends AbstractRawEntity
+{
+    protected array $serviceProviderMetadata;
+    protected array $userAttributes;
+    protected DateTimeImmutable $happenedAt;
+    protected ?string $clientIpAddress;
+
+    public function __construct(array $rawRow, AbstractPlatform $abstractPlatform)
+    {
+        parent::__construct($rawRow, $abstractPlatform);
+
+        $this->serviceProviderMetadata = $this->resolveServiceProviderMetadata(
+            (string)$rawRow[TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_SP_METADATA]
+        );
+
+        $this->userAttributes = $this->resolveUserAttributes(
+            (string)$rawRow[TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_USER_ATTRIBUTES]
+        );
+
+        $this->happenedAt = $this->resolveDateTimeImmutable(
+            $rawRow[TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_HAPPENED_AT]
+        );
+
+        $this->clientIpAddress = empty($rawRow[TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_CLIENT_IP_ADDRESS]) ?
+            null :
+            (string)$rawRow[TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_CLIENT_IP_ADDRESS];
+    }
+
+    /**
+     * @return DateTimeImmutable
+     */
+    public function getHappenedAt(): DateTimeImmutable
+    {
+        return $this->happenedAt;
+    }
+
+    /**
+     * @return array
+     */
+    public function getServiceProviderMetadata(): array
+    {
+        return $this->serviceProviderMetadata;
+    }
+
+    /**
+     * @return array
+     */
+    public function getUserAttributes(): array
+    {
+        return $this->userAttributes;
+    }
+
+    /**
+     * @return string|null
+     */
+    public function getClientIpAddress(): ?string
+    {
+        return $this->clientIpAddress;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    protected function validate(array $rawRow): void
+    {
+        $columnsToCheck = [
+            TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_SP_METADATA,
+            TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_USER_ATTRIBUTES,
+            TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_HAPPENED_AT,
+        ];
+
+        foreach ($columnsToCheck as $column) {
+            if (empty($rawRow[$column])) {
+                throw new UnexpectedValueException(sprintf('Column %s must be set.', $column));
+            }
+        }
+
+        if (! is_string($rawRow[TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_SP_METADATA])) {
+            $message = sprintf(
+                'Column %s must be string.',
+                TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_SP_METADATA
+            );
+            throw new UnexpectedValueException($message);
+        }
+
+        if (! is_string($rawRow[TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_USER_ATTRIBUTES])) {
+            $message = sprintf(
+                'Column %s must be string.',
+                TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_USER_ATTRIBUTES
+            );
+            throw new UnexpectedValueException($message);
+        }
+
+        if (! is_string($rawRow[TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_HAPPENED_AT])) {
+            $message = sprintf(
+                'Column %s must be string.',
+                TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_HAPPENED_AT
+            );
+            throw new UnexpectedValueException($message);
+        }
+    }
+
+    protected function resolveServiceProviderMetadata(string $serializedMetadata): array
+    {
+        /** @psalm-suppress MixedAssignment - we check the type manually */
+        $metadata = unserialize($serializedMetadata);
+
+        if (is_array($metadata)) {
+            return $metadata;
+        }
+
+        $message = sprintf('Metadata not in expected array format, got type %s.', gettype($metadata));
+        throw new UnexpectedValueException($message);
+    }
+
+    protected function resolveUserAttributes(string $serializedUserAttributes): array
+    {
+        /** @psalm-suppress MixedAssignment - we check the type manually */
+        $userAttributes = unserialize($serializedUserAttributes);
+
+        if (is_array($userAttributes)) {
+            return $userAttributes;
+        }
+
+        $message = sprintf('User attributes not in expected array format, got type %s.', gettype($userAttributes));
+        throw new UnexpectedValueException($message);
+    }
+}
diff --git a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawConnectedServiceProvider.php b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawConnectedServiceProvider.php
new file mode 100644
index 0000000..f9ed95a
--- /dev/null
+++ b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawConnectedServiceProvider.php
@@ -0,0 +1,170 @@
+<?php
+
+namespace SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store;
+
+use DateTimeImmutable;
+use Doctrine\DBAL\Platforms\AbstractPlatform;
+use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+use SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractRawEntity;
+
+class RawConnectedServiceProvider extends AbstractRawEntity
+{
+    protected int $numberOfAuthentications;
+    protected DateTimeImmutable $lastAuthenticationAt;
+    protected DateTimeImmutable $firstAuthenticationAt;
+    protected array $serviceProviderMetadata;
+    protected array $userAttributes;
+
+    public function __construct(array $rawRow, AbstractPlatform $abstractPlatform)
+    {
+        parent::__construct($rawRow, $abstractPlatform);
+
+        $this->numberOfAuthentications = (int)$rawRow[
+            TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_NUMBER_OF_AUTHENTICATIONS
+        ];
+
+        $this->lastAuthenticationAt = $this->resolveDateTimeImmutable(
+            $rawRow[TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_LAST_AUTHENTICATION_AT]
+        );
+
+        $this->firstAuthenticationAt = $this->resolveDateTimeImmutable(
+            $rawRow[TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_FIRST_AUTHENTICATION_AT]
+        );
+
+        $this->serviceProviderMetadata = $this->resolveServiceProviderMetadata(
+            (string)$rawRow[TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_SP_METADATA]
+        );
+
+        $this->userAttributes = $this->resolveUserAttributes(
+            (string)$rawRow[TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_USER_ATTRIBUTES]
+        );
+    }
+
+    /**
+     * @return int
+     */
+    public function getNumberOfAuthentications(): int
+    {
+        return $this->numberOfAuthentications;
+    }
+
+    /**
+     * @return DateTimeImmutable
+     */
+    public function getLastAuthenticationAt(): DateTimeImmutable
+    {
+        return $this->lastAuthenticationAt;
+    }
+
+    /**
+     * @return DateTimeImmutable
+     */
+    public function getFirstAuthenticationAt(): DateTimeImmutable
+    {
+        return $this->firstAuthenticationAt;
+    }
+
+    /**
+     * @return array
+     */
+    public function getServiceProviderMetadata(): array
+    {
+        return $this->serviceProviderMetadata;
+    }
+
+    /**
+     * @return array
+     */
+    public function getUserAttributes(): array
+    {
+        return $this->userAttributes;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    protected function validate(array $rawRow): void
+    {
+        $columnsToCheck = [
+            TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_NUMBER_OF_AUTHENTICATIONS,
+            TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_LAST_AUTHENTICATION_AT,
+            TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_FIRST_AUTHENTICATION_AT,
+            TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_SP_METADATA,
+            TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_USER_ATTRIBUTES,
+        ];
+
+        foreach ($columnsToCheck as $column) {
+            if (empty($rawRow[$column])) {
+                throw new UnexpectedValueException(sprintf('Column %s must be set.', $column));
+            }
+        }
+
+        if (
+            ! is_numeric($rawRow[TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_NUMBER_OF_AUTHENTICATIONS])
+        ) {
+            $message = sprintf(
+                'Column %s must be numeric.',
+                TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_NUMBER_OF_AUTHENTICATIONS
+            );
+            throw new UnexpectedValueException($message);
+        }
+
+        if (! is_string($rawRow[TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_LAST_AUTHENTICATION_AT])) {
+            $message = sprintf(
+                'Column %s must be string.',
+                TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_LAST_AUTHENTICATION_AT
+            );
+            throw new UnexpectedValueException($message);
+        }
+
+        if (! is_string($rawRow[TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_FIRST_AUTHENTICATION_AT])) {
+            $message = sprintf(
+                'Column %s must be string.',
+                TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_FIRST_AUTHENTICATION_AT
+            );
+            throw new UnexpectedValueException($message);
+        }
+
+        if (! is_string($rawRow[TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_SP_METADATA])) {
+            $message = sprintf(
+                'Column %s must be string.',
+                TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_SP_METADATA
+            );
+            throw new UnexpectedValueException($message);
+        }
+
+        if (! is_string($rawRow[TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_USER_ATTRIBUTES])) {
+            $message = sprintf(
+                'Column %s must be string.',
+                TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_USER_ATTRIBUTES
+            );
+            throw new UnexpectedValueException($message);
+        }
+    }
+
+    protected function resolveServiceProviderMetadata(string $serializedMetadata): array
+    {
+        /** @psalm-suppress MixedAssignment - we check the type manually */
+        $metadata = unserialize($serializedMetadata);
+
+        if (is_array($metadata)) {
+            return $metadata;
+        }
+
+        $message = sprintf('Metadata not in expected array format, got type %s.', gettype($metadata));
+        throw new UnexpectedValueException($message);
+    }
+
+    protected function resolveUserAttributes(string $serializedUserAttributes): array
+    {
+        /** @psalm-suppress MixedAssignment - we check the type manually */
+        $userAttributes = unserialize($serializedUserAttributes);
+
+        if (is_array($userAttributes)) {
+            return $userAttributes;
+        }
+
+        $message = sprintf('User attributes not in expected array format, got type %s.', gettype($userAttributes));
+        throw new UnexpectedValueException($message);
+    }
+}
diff --git a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Repository.php b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Repository.php
new file mode 100644
index 0000000..24c9b34
--- /dev/null
+++ b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Repository.php
@@ -0,0 +1,1093 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store;
+
+use Doctrine\DBAL\ParameterType;
+use Doctrine\DBAL\Result;
+use Doctrine\DBAL\Types\Types;
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Module\accounting\Exceptions\StoreException;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection;
+use Throwable;
+
+class Repository
+{
+    protected Connection $connection;
+    protected LoggerInterface $logger;
+    protected string $tableNameIdp;
+    protected string $tableNameIdpVersion;
+    protected string $tableNameSp;
+    protected string $tableNameSpVersion;
+    protected string $tableNameUser;
+    protected string $tableNameUserVersion;
+    protected string $tableNameIdpSpUserVersion;
+    protected string $tableNameAuthenticationEvent;
+
+    public function __construct(Connection $connection, LoggerInterface $logger)
+    {
+        $this->connection = $connection;
+        $this->logger = $logger;
+
+        $this->tableNameIdp = $this->preparePrefixedTableName(TableConstants::TABLE_NAME_IDP);
+        $this->tableNameIdpVersion = $this->preparePrefixedTableName(TableConstants::TABLE_NAME_IDP_VERSION);
+        $this->tableNameSp = $this->preparePrefixedTableName(TableConstants::TABLE_NAME_SP);
+        $this->tableNameSpVersion = $this->preparePrefixedTableName(TableConstants::TABLE_NAME_SP_VERSION);
+        $this->tableNameUser = $this->preparePrefixedTableName(TableConstants::TABLE_NAME_USER);
+        $this->tableNameUserVersion = $this->preparePrefixedTableName(TableConstants::TABLE_NAME_USER_VERSION);
+        $this->tableNameIdpSpUserVersion =
+            $this->preparePrefixedTableName(TableConstants::TABLE_NAME_IDP_SP_USER_VERSION);
+        $this->tableNameAuthenticationEvent =
+            $this->preparePrefixedTableName(TableConstants::TABLE_NAME_AUTHENTICATION_EVENT);
+    }
+
+    protected function preparePrefixedTableName(string $tableName): string
+    {
+        return $this->connection->preparePrefixedTableName(TableConstants::TABLE_PREFIX . $tableName);
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function getIdp(string $entityIdHashSha256): Result
+    {
+        try {
+            $queryBuilder = $this->connection->dbal()->createQueryBuilder();
+
+            /** @psalm-suppress TooManyArguments */
+            $queryBuilder->select(
+                TableConstants::TABLE_IDP_COLUMN_NAME_ID,
+                TableConstants::TABLE_IDP_COLUMN_NAME_ENTITY_ID,
+                TableConstants::TABLE_IDP_COLUMN_NAME_ENTITY_ID_HASH_SHA256,
+                TableConstants::TABLE_IDP_COLUMN_NAME_CREATED_AT,
+            )
+                ->from($this->tableNameIdp)
+                ->where(
+                    TableConstants::TABLE_IDP_COLUMN_NAME_ENTITY_ID_HASH_SHA256 . ' = ' .
+                    $queryBuilder->createNamedParameter($entityIdHashSha256)
+                )->setMaxResults(1);
+
+            return $queryBuilder->executeQuery();
+        } catch (Throwable $exception) {
+            $message = sprintf(
+                'Error executing query to get IdP by entity ID hash SHA256 \'%s\'. Error was: %s.',
+                $entityIdHashSha256,
+                $exception->getMessage()
+            );
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function insertIdp(
+        string $entityId,
+        string $entityIdHashSha256,
+        \DateTimeImmutable $createdAt = null
+    ): void {
+        $queryBuilder = $this->connection->dbal()->createQueryBuilder();
+
+        $createdAt = $createdAt ?? new \DateTimeImmutable();
+
+        $queryBuilder->insert($this->tableNameIdp)
+            ->values(
+                [
+                    TableConstants::TABLE_IDP_COLUMN_NAME_ENTITY_ID => ':' .
+                        TableConstants::TABLE_IDP_COLUMN_NAME_ENTITY_ID,
+                    TableConstants::TABLE_IDP_COLUMN_NAME_ENTITY_ID_HASH_SHA256 => ':' .
+                        TableConstants::TABLE_IDP_COLUMN_NAME_ENTITY_ID_HASH_SHA256,
+                    TableConstants::TABLE_IDP_COLUMN_NAME_CREATED_AT => ':' .
+                        TableConstants::TABLE_IDP_COLUMN_NAME_CREATED_AT,
+                ]
+            )
+            ->setParameters(
+                [
+                    TableConstants::TABLE_IDP_COLUMN_NAME_ENTITY_ID => $entityId,
+                    TableConstants::TABLE_IDP_COLUMN_NAME_ENTITY_ID_HASH_SHA256 => $entityIdHashSha256,
+                    TableConstants::TABLE_IDP_COLUMN_NAME_CREATED_AT => $createdAt,
+                ],
+                [
+                    TableConstants::TABLE_IDP_COLUMN_NAME_ENTITY_ID => Types::STRING,
+                    TableConstants::TABLE_IDP_COLUMN_NAME_ENTITY_ID_HASH_SHA256 => Types::STRING,
+                    TableConstants::TABLE_IDP_COLUMN_NAME_CREATED_AT => Types::DATETIMETZ_IMMUTABLE
+                ]
+            );
+
+        try {
+            $queryBuilder->executeStatement();
+        } catch (Throwable $exception) {
+            $message = sprintf('Error executing query to insert IdP. Error was: %s.', $exception->getMessage());
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function getIdpVersion(int $idpId, string $metadataHashSha256): Result
+    {
+        try {
+            $queryBuilder = $this->connection->dbal()->createQueryBuilder();
+
+            /** @psalm-suppress TooManyArguments */
+            $queryBuilder->select(
+                TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_ID,
+                TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_IDP_ID,
+                TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_METADATA,
+                TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_METADATA_HASH_SHA256,
+                TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_CREATED_AT,
+            )
+                ->from($this->tableNameIdpVersion)
+                ->where(
+                    $queryBuilder->expr()->and(
+                        $queryBuilder->expr()->eq(
+                            TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_IDP_ID,
+                            $queryBuilder->createNamedParameter($idpId, ParameterType::INTEGER)
+                        ),
+                        $queryBuilder->expr()->eq(
+                            TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_METADATA_HASH_SHA256,
+                            $queryBuilder->createNamedParameter($metadataHashSha256)
+                        )
+                    )
+                )->setMaxResults(1);
+
+            return $queryBuilder->executeQuery();
+        } catch (Throwable $exception) {
+            $message = sprintf(
+                'Error executing query to get IdP Version for IdP %s and metadata array hash %s. Error was: %s.',
+                $idpId,
+                $metadataHashSha256,
+                $exception->getMessage()
+            );
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function insertIdpVersion(
+        int $idpId,
+        string $metadata,
+        string $metadataHashSha256,
+        \DateTimeImmutable $createdAt = null
+    ): void {
+        $queryBuilder = $this->connection->dbal()->createQueryBuilder();
+
+        $createdAt = $createdAt ?? new \DateTimeImmutable();
+
+        $queryBuilder->insert($this->tableNameIdpVersion)
+            ->values(
+                [
+                    TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_IDP_ID => ':' .
+                        TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_IDP_ID,
+                    TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_METADATA => ':' .
+                        TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_METADATA,
+                    TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_METADATA_HASH_SHA256 => ':' .
+                        TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_METADATA_HASH_SHA256,
+                    TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_CREATED_AT => ':' .
+                        TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_CREATED_AT,
+                ]
+            )
+            ->setParameters(
+                [
+                    TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_IDP_ID => $idpId,
+                    TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_METADATA => $metadata,
+                    TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_METADATA_HASH_SHA256 => $metadataHashSha256,
+                    TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_CREATED_AT => $createdAt,
+                ],
+                [
+                    TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_IDP_ID => Types::BIGINT,
+                    TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_METADATA => Types::TEXT,
+                    TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_METADATA_HASH_SHA256 => Types::STRING,
+                    TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_CREATED_AT => Types::DATETIMETZ_IMMUTABLE,
+                ]
+            );
+
+        try {
+            $queryBuilder->executeStatement();
+        } catch (Throwable $exception) {
+            $message = sprintf('Error executing query to insert IdP Version. Error was: %s.', $exception->getMessage());
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function getSp(string $entityIdHashSha256): Result
+    {
+        try {
+            $queryBuilder = $this->connection->dbal()->createQueryBuilder();
+
+            /** @psalm-suppress TooManyArguments */
+            $queryBuilder->select(
+                TableConstants::TABLE_SP_COLUMN_NAME_ID,
+                TableConstants::TABLE_SP_COLUMN_NAME_ENTITY_ID,
+                TableConstants::TABLE_SP_COLUMN_NAME_ENTITY_ID_HASH_SHA256,
+                TableConstants::TABLE_SP_COLUMN_NAME_CREATED_AT,
+            )
+                ->from($this->tableNameSp)
+                ->where(
+                    TableConstants::TABLE_SP_COLUMN_NAME_ENTITY_ID_HASH_SHA256 . ' = ' .
+                    $queryBuilder->createNamedParameter($entityIdHashSha256)
+                )->setMaxResults(1);
+
+            return $queryBuilder->executeQuery();
+        } catch (Throwable $exception) {
+            $message = sprintf(
+                'Error executing query to get SP by entity ID hash SHA256 \'%s\'. Error was: %s.',
+                $entityIdHashSha256,
+                $exception->getMessage()
+            );
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    public function insertSp(
+        string $entityId,
+        string $entityIdHashSha256,
+        \DateTimeImmutable $createdAt = null
+    ): void {
+        $queryBuilder = $this->connection->dbal()->createQueryBuilder();
+
+        $createdAt = $createdAt ?? new \DateTimeImmutable();
+
+        $queryBuilder->insert($this->tableNameSp)
+            ->values(
+                [
+                    TableConstants::TABLE_SP_COLUMN_NAME_ENTITY_ID => ':' .
+                        TableConstants::TABLE_SP_COLUMN_NAME_ENTITY_ID,
+                    TableConstants::TABLE_SP_COLUMN_NAME_ENTITY_ID_HASH_SHA256 => ':' .
+                        TableConstants::TABLE_SP_COLUMN_NAME_ENTITY_ID_HASH_SHA256,
+                    TableConstants::TABLE_SP_COLUMN_NAME_CREATED_AT => ':' .
+                        TableConstants::TABLE_SP_COLUMN_NAME_CREATED_AT,
+                ]
+            )
+            ->setParameters(
+                [
+                    TableConstants::TABLE_SP_COLUMN_NAME_ENTITY_ID => $entityId,
+                    TableConstants::TABLE_SP_COLUMN_NAME_ENTITY_ID_HASH_SHA256 => $entityIdHashSha256,
+                    TableConstants::TABLE_SP_COLUMN_NAME_CREATED_AT => $createdAt,
+                ],
+                [
+                    TableConstants::TABLE_SP_COLUMN_NAME_ENTITY_ID => Types::STRING,
+                    TableConstants::TABLE_SP_COLUMN_NAME_ENTITY_ID_HASH_SHA256 => Types::STRING,
+                    TableConstants::TABLE_SP_COLUMN_NAME_CREATED_AT => Types::DATETIMETZ_IMMUTABLE
+                ]
+            );
+
+        try {
+            $queryBuilder->executeStatement();
+        } catch (Throwable $exception) {
+            $message = sprintf('Error executing query to insert SP. Error was: %s.', $exception->getMessage());
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function getSpVersion(int $spId, string $metadataHashSha256): Result
+    {
+        try {
+            $queryBuilder = $this->connection->dbal()->createQueryBuilder();
+
+            /** @psalm-suppress TooManyArguments */
+            $queryBuilder->select(
+                TableConstants::TABLE_SP_VERSION_COLUMN_NAME_ID,
+                TableConstants::TABLE_SP_VERSION_COLUMN_NAME_SP_ID,
+                TableConstants::TABLE_SP_VERSION_COLUMN_NAME_METADATA,
+                TableConstants::TABLE_SP_VERSION_COLUMN_NAME_METADATA_HASH_SHA256,
+                TableConstants::TABLE_SP_VERSION_COLUMN_NAME_CREATED_AT,
+            )
+                ->from($this->tableNameSpVersion)
+                ->where(
+                    $queryBuilder->expr()->and(
+                        $queryBuilder->expr()->eq(
+                            TableConstants::TABLE_SP_VERSION_COLUMN_NAME_SP_ID,
+                            $queryBuilder->createNamedParameter($spId, ParameterType::INTEGER)
+                        ),
+                        $queryBuilder->expr()->eq(
+                            TableConstants::TABLE_SP_VERSION_COLUMN_NAME_METADATA_HASH_SHA256,
+                            $queryBuilder->createNamedParameter($metadataHashSha256)
+                        )
+                    )
+                )->setMaxResults(1);
+
+            return $queryBuilder->executeQuery();
+        } catch (Throwable $exception) {
+            $message = sprintf(
+                'Error executing query to get SP Version for SP %s and metadata array hash %s. Error was: %s.',
+                $spId,
+                $metadataHashSha256,
+                $exception->getMessage()
+            );
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function insertSpVersion(
+        int $spId,
+        string $metadata,
+        string $metadataHashSha256,
+        \DateTimeImmutable $createdAt = null
+    ): void {
+        $queryBuilder = $this->connection->dbal()->createQueryBuilder();
+
+        $createdAt = $createdAt ?? new \DateTimeImmutable();
+
+        $queryBuilder->insert($this->tableNameSpVersion)
+            ->values(
+                [
+                    TableConstants::TABLE_SP_VERSION_COLUMN_NAME_SP_ID => ':' .
+                        TableConstants::TABLE_SP_VERSION_COLUMN_NAME_SP_ID,
+                    TableConstants::TABLE_SP_VERSION_COLUMN_NAME_METADATA => ':' .
+                        TableConstants::TABLE_SP_VERSION_COLUMN_NAME_METADATA,
+                    TableConstants::TABLE_SP_VERSION_COLUMN_NAME_METADATA_HASH_SHA256 => ':' .
+                        TableConstants::TABLE_SP_VERSION_COLUMN_NAME_METADATA_HASH_SHA256,
+                    TableConstants::TABLE_SP_VERSION_COLUMN_NAME_CREATED_AT => ':' .
+                        TableConstants::TABLE_SP_VERSION_COLUMN_NAME_CREATED_AT,
+                ]
+            )
+            ->setParameters(
+                [
+                    TableConstants::TABLE_SP_VERSION_COLUMN_NAME_SP_ID => $spId,
+                    TableConstants::TABLE_SP_VERSION_COLUMN_NAME_METADATA => $metadata,
+                    TableConstants::TABLE_SP_VERSION_COLUMN_NAME_METADATA_HASH_SHA256 => $metadataHashSha256,
+                    TableConstants::TABLE_SP_VERSION_COLUMN_NAME_CREATED_AT => $createdAt,
+                ],
+                [
+                    TableConstants::TABLE_SP_VERSION_COLUMN_NAME_SP_ID => Types::BIGINT,
+                    TableConstants::TABLE_SP_VERSION_COLUMN_NAME_METADATA => Types::TEXT,
+                    TableConstants::TABLE_SP_VERSION_COLUMN_NAME_METADATA_HASH_SHA256 => Types::STRING,
+                    TableConstants::TABLE_SP_VERSION_COLUMN_NAME_CREATED_AT => Types::DATETIMETZ_IMMUTABLE,
+                ]
+            );
+
+        try {
+            $queryBuilder->executeStatement();
+        } catch (Throwable $exception) {
+            $message = sprintf('Error executing query to insert SP Version. Error was: %s.', $exception->getMessage());
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function getUser(string $identifierHashSha256): Result
+    {
+        try {
+            $queryBuilder = $this->connection->dbal()->createQueryBuilder();
+
+            /** @psalm-suppress TooManyArguments */
+            $queryBuilder->select(
+                TableConstants::TABLE_USER_COLUMN_NAME_ID,
+                TableConstants::TABLE_USER_COLUMN_NAME_IDENTIFIER,
+                TableConstants::TABLE_USER_COLUMN_NAME_IDENTIFIER_HASH_SHA256,
+                TableConstants::TABLE_USER_COLUMN_NAME_CREATED_AT,
+            )
+                ->from($this->tableNameUser)
+                ->where(
+                    TableConstants::TABLE_USER_COLUMN_NAME_IDENTIFIER_HASH_SHA256 . ' = ' .
+                    $queryBuilder->createNamedParameter($identifierHashSha256)
+                )->setMaxResults(1);
+
+            return $queryBuilder->executeQuery();
+        } catch (Throwable $exception) {
+            $message = sprintf(
+                'Error executing query to get user by identifier hash SHA256 \'%s\'. Error was: %s.',
+                $identifierHashSha256,
+                $exception->getMessage()
+            );
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function insertUser(
+        string $identifier,
+        string $identifierHashSha256,
+        \DateTimeImmutable $createdAt = null
+    ): void {
+        $queryBuilder = $this->connection->dbal()->createQueryBuilder();
+
+        $createdAt = $createdAt ?? new \DateTimeImmutable();
+
+        $queryBuilder->insert($this->tableNameUser)
+            ->values(
+                [
+                    TableConstants::TABLE_USER_COLUMN_NAME_IDENTIFIER => ':' .
+                        TableConstants::TABLE_USER_COLUMN_NAME_IDENTIFIER,
+                    TableConstants::TABLE_USER_COLUMN_NAME_IDENTIFIER_HASH_SHA256 => ':' .
+                        TableConstants::TABLE_USER_COLUMN_NAME_IDENTIFIER_HASH_SHA256,
+                    TableConstants::TABLE_USER_COLUMN_NAME_CREATED_AT => ':' .
+                        TableConstants::TABLE_USER_COLUMN_NAME_CREATED_AT,
+                ]
+            )
+            ->setParameters(
+                [
+                    TableConstants::TABLE_USER_COLUMN_NAME_IDENTIFIER => $identifier,
+                    TableConstants::TABLE_USER_COLUMN_NAME_IDENTIFIER_HASH_SHA256 => $identifierHashSha256,
+                    TableConstants::TABLE_USER_COLUMN_NAME_CREATED_AT => $createdAt,
+                ],
+                [
+                    TableConstants::TABLE_USER_COLUMN_NAME_IDENTIFIER => Types::TEXT,
+                    TableConstants::TABLE_USER_COLUMN_NAME_IDENTIFIER_HASH_SHA256 => Types::STRING,
+                    TableConstants::TABLE_USER_COLUMN_NAME_CREATED_AT => Types::DATETIMETZ_IMMUTABLE
+                ]
+            );
+
+        try {
+            $queryBuilder->executeStatement();
+        } catch (Throwable $exception) {
+            $message = sprintf('Error executing query to insert user. Error was: %s.', $exception->getMessage());
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function getUserVersion(int $userId, string $attributesHashSha256): Result
+    {
+        try {
+            $queryBuilder = $this->connection->dbal()->createQueryBuilder();
+
+            /** @psalm-suppress TooManyArguments */
+            $queryBuilder->select(
+                TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ID,
+                TableConstants::TABLE_USER_VERSION_COLUMN_NAME_USER_ID,
+                TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ATTRIBUTES,
+                TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ATTRIBUTES_HASH_SHA256,
+                TableConstants::TABLE_USER_VERSION_COLUMN_NAME_CREATED_AT,
+            )
+                ->from($this->tableNameUserVersion)
+                ->where(
+                    $queryBuilder->expr()->and(
+                        $queryBuilder->expr()->eq(
+                            TableConstants::TABLE_USER_VERSION_COLUMN_NAME_USER_ID,
+                            $queryBuilder->createNamedParameter($userId, ParameterType::INTEGER)
+                        ),
+                        $queryBuilder->expr()->eq(
+                            TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ATTRIBUTES_HASH_SHA256,
+                            $queryBuilder->createNamedParameter($attributesHashSha256)
+                        )
+                    )
+                )->setMaxResults(1);
+
+            return $queryBuilder->executeQuery();
+        } catch (Throwable $exception) {
+            $message = sprintf(
+                'Error executing query to get user version for user ID %s and attribute array hash %s. Error was: %s.',
+                $userId,
+                $attributesHashSha256,
+                $exception->getMessage()
+            );
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function insertUserVersion(
+        int $userId,
+        string $attributes,
+        string $attributesHashSha256,
+        \DateTimeImmutable $createdAt = null
+    ): void {
+        $queryBuilder = $this->connection->dbal()->createQueryBuilder();
+
+        $createdAt = $createdAt ?? new \DateTimeImmutable();
+
+        $queryBuilder->insert($this->tableNameUserVersion)
+            ->values(
+                [
+                    TableConstants::TABLE_USER_VERSION_COLUMN_NAME_USER_ID => ':' .
+                        TableConstants::TABLE_USER_VERSION_COLUMN_NAME_USER_ID,
+                    TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ATTRIBUTES => ':' .
+                        TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ATTRIBUTES,
+                    TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ATTRIBUTES_HASH_SHA256 => ':' .
+                        TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ATTRIBUTES_HASH_SHA256,
+                    TableConstants::TABLE_USER_VERSION_COLUMN_NAME_CREATED_AT => ':' .
+                        TableConstants::TABLE_USER_VERSION_COLUMN_NAME_CREATED_AT,
+                ]
+            )
+            ->setParameters(
+                [
+                    TableConstants::TABLE_USER_VERSION_COLUMN_NAME_USER_ID => $userId,
+                    TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ATTRIBUTES => $attributes,
+                    TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ATTRIBUTES_HASH_SHA256 => $attributesHashSha256,
+                    TableConstants::TABLE_USER_VERSION_COLUMN_NAME_CREATED_AT => $createdAt,
+                ],
+                [
+                    TableConstants::TABLE_USER_VERSION_COLUMN_NAME_USER_ID => Types::BIGINT,
+                    TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ATTRIBUTES => Types::TEXT,
+                    TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ATTRIBUTES_HASH_SHA256 => Types::STRING,
+                    TableConstants::TABLE_USER_VERSION_COLUMN_NAME_CREATED_AT => Types::DATETIMETZ_IMMUTABLE,
+                ]
+            );
+
+        try {
+            $queryBuilder->executeStatement();
+        } catch (Throwable $exception) {
+            $message = sprintf(
+                'Error executing query to insert user version. Error was: %s.',
+                $exception->getMessage()
+            );
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function getIdpSpUserVersion(int $idpVersionId, int $spVersionId, int $userVersionId): Result
+    {
+        try {
+            $queryBuilder = $this->connection->dbal()->createQueryBuilder();
+
+            /** @psalm-suppress TooManyArguments */
+            $queryBuilder->select(
+                TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_ID,
+                TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_IDP_VERSION_ID,
+                TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_SP_VERSION_ID,
+                TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_USER_VERSION_ID,
+                TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_CREATED_AT,
+            )
+                ->from($this->tableNameIdpSpUserVersion)
+                ->where(
+                    $queryBuilder->expr()->and(
+                        $queryBuilder->expr()->eq(
+                            TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_IDP_VERSION_ID,
+                            $queryBuilder->createNamedParameter($idpVersionId, ParameterType::INTEGER)
+                        ),
+                        $queryBuilder->expr()->eq(
+                            TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_SP_VERSION_ID,
+                            $queryBuilder->createNamedParameter($spVersionId, ParameterType::INTEGER)
+                        ),
+                        $queryBuilder->expr()->eq(
+                            TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_USER_VERSION_ID,
+                            $queryBuilder->createNamedParameter($userVersionId, ParameterType::INTEGER)
+                        )
+                    )
+                )->setMaxResults(1);
+
+            return $queryBuilder->executeQuery();
+        } catch (Throwable $exception) {
+            $message = sprintf(
+                'Error executing query to get IdpSpUserVersion for IdpVersion %s, SpVersion %s and UserVersion %s.' .
+                ' Error was: %s.',
+                $idpVersionId,
+                $spVersionId,
+                $userVersionId,
+                $exception->getMessage()
+            );
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function insertIdpSpUserVersion(
+        int $idpVersionId,
+        int $spVersionId,
+        int $userVersionId,
+        \DateTimeImmutable $createdAt = null
+    ): void {
+        $queryBuilder = $this->connection->dbal()->createQueryBuilder();
+
+        $createdAt = $createdAt ?? new \DateTimeImmutable();
+
+        $queryBuilder->insert($this->tableNameIdpSpUserVersion)
+            ->values(
+                [
+                    TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_IDP_VERSION_ID => ':' .
+                        TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_IDP_VERSION_ID,
+                    TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_SP_VERSION_ID => ':' .
+                        TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_SP_VERSION_ID,
+                    TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_USER_VERSION_ID => ':' .
+                        TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_USER_VERSION_ID,
+                    TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_CREATED_AT => ':' .
+                        TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_CREATED_AT,
+                ]
+            )
+            ->setParameters(
+                [
+                    TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_IDP_VERSION_ID => $idpVersionId,
+                    TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_SP_VERSION_ID => $spVersionId,
+                    TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_USER_VERSION_ID => $userVersionId,
+                    TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_CREATED_AT => $createdAt,
+                ],
+                [
+                    TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_IDP_VERSION_ID => Types::BIGINT,
+                    TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_SP_VERSION_ID => Types::BIGINT,
+                    TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_USER_VERSION_ID => Types::BIGINT,
+                    TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_CREATED_AT => Types::DATETIMETZ_IMMUTABLE
+                ]
+            );
+
+        try {
+            $queryBuilder->executeStatement();
+        } catch (Throwable $exception) {
+            $message = sprintf(
+                'Error executing query to insert IdpSpUserVersion. Error was: %s.',
+                $exception->getMessage()
+            );
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function insertAuthenticationEvent(
+        int $IdpSpUserVersionId,
+        \DateTimeImmutable $happenedAt,
+        string $clientIpAddress = null,
+        \DateTimeImmutable $createdAt = null
+    ): void {
+        try {
+            $queryBuilder = $this->connection->dbal()->createQueryBuilder();
+
+            $createdAt = $createdAt ?? new \DateTimeImmutable();
+
+            $queryBuilder->insert($this->tableNameAuthenticationEvent)
+                ->values(
+                    [
+                        TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_IDP_SP_USER_VERSION_ID => ':' .
+                            TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_IDP_SP_USER_VERSION_ID,
+                        TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_HAPPENED_AT => ':' .
+                            TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_HAPPENED_AT,
+                        TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_CLIENT_IP_ADDRESS => ':' .
+                            TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_CLIENT_IP_ADDRESS,
+                        TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_CREATED_AT => ':' .
+                            TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_CREATED_AT,
+                    ]
+                )
+                ->setParameters(
+                    [
+                        TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_IDP_SP_USER_VERSION_ID =>
+                            $IdpSpUserVersionId,
+                        TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_HAPPENED_AT => $happenedAt,
+                        TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_CLIENT_IP_ADDRESS => $clientIpAddress,
+                        TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_CREATED_AT => $createdAt,
+                    ],
+                    [
+                        TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_IDP_SP_USER_VERSION_ID =>
+                            Types::BIGINT,
+                        TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_HAPPENED_AT =>
+                            Types::DATETIMETZ_IMMUTABLE,
+                        TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_CLIENT_IP_ADDRESS =>
+                            Types::STRING,
+                        TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_CREATED_AT =>
+                            Types::DATETIMETZ_IMMUTABLE,
+                    ]
+                );
+
+            $queryBuilder->executeStatement();
+        } catch (Throwable $exception) {
+            $message = sprintf(
+                'Error executing query to insert AuthenticationEvent. Error was: %s.',
+                $exception->getMessage()
+            );
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function getConnectedServiceProviders(string $userIdentifierHashSha256): array
+    {
+        try {
+            $authenticationEventsQueryBuilder = $this->connection->dbal()->createQueryBuilder();
+            $lastMetadataAndAttributesQueryBuilder = $this->connection->dbal()->createQueryBuilder();
+
+            /** @psalm-suppress TooManyArguments */
+            $authenticationEventsQueryBuilder->select(
+                //'vs.entity_id AS sp_entity_id',
+                TableConstants::TABLE_ALIAS_SP . '.' .
+                TableConstants::TABLE_SP_COLUMN_NAME_ENTITY_ID . ' AS ' .
+                TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_SP_ENTITY_ID,
+                //'COUNT(vae.id) AS number_of_authentications',
+                'COUNT(' .  TableConstants::TABLE_ALIAS_AUTHENTICATION_EVENT . '.' .
+                TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_ID . ') AS ' .
+                TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_NUMBER_OF_AUTHENTICATIONS,
+                //'MAX(vae.happened_at) AS last_authentication_at',
+                'MAX(' .  TableConstants::TABLE_ALIAS_AUTHENTICATION_EVENT . '.' .
+                TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_HAPPENED_AT . ') AS ' .
+                TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_LAST_AUTHENTICATION_AT,
+                //'MIN(vae.happened_at) AS first_authentication_at',
+                'MIN(' .  TableConstants::TABLE_ALIAS_AUTHENTICATION_EVENT . '.' .
+                TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_HAPPENED_AT . ') AS ' .
+                TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_FIRST_AUTHENTICATION_AT,
+            )->from($this->tableNameAuthenticationEvent, TableConstants::TABLE_ALIAS_AUTHENTICATION_EVENT)
+                ->leftJoin(
+                    //'vae',
+                    TableConstants::TABLE_ALIAS_AUTHENTICATION_EVENT,
+                    //'vds_idp_sp_user_version',
+                    $this->tableNameIdpSpUserVersion,
+                    //'visuv',
+                    TableConstants::TABLE_ALIAS_IDP_SP_USER_VERSION,
+                    //'vae.idp_sp_user_version_id = visuv.id'
+                    TableConstants::TABLE_ALIAS_AUTHENTICATION_EVENT . '.' .
+                    TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_IDP_SP_USER_VERSION_ID . ' = ' .
+                    TableConstants::TABLE_ALIAS_IDP_SP_USER_VERSION . '.' .
+                    TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_ID
+                )
+                ->leftJoin(
+                    //'visuv',
+                    TableConstants::TABLE_ALIAS_IDP_SP_USER_VERSION,
+                    //'vds_sp_version',
+                    $this->tableNameSpVersion,
+                    //'vsv',
+                    TableConstants::TABLE_ALIAS_SP_VERSION,
+                    //'visuv.sp_version_id = vsv.id'
+                    TableConstants::TABLE_ALIAS_IDP_SP_USER_VERSION . '.' .
+                    TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_SP_VERSION_ID . ' = ' .
+                    TableConstants::TABLE_ALIAS_SP_VERSION . '.' . TableConstants::TABLE_SP_VERSION_COLUMN_NAME_ID
+                )
+                ->leftJoin(
+                    //'vsv',
+                    TableConstants::TABLE_ALIAS_SP_VERSION,
+                    //'vds_sp',
+                    $this->tableNameSp,
+                    //'vs',
+                    TableConstants::TABLE_ALIAS_SP,
+                    //'vsv.sp_id = vs.id'
+                    TableConstants::TABLE_ALIAS_SP_VERSION . '.' .
+                    TableConstants::TABLE_SP_VERSION_COLUMN_NAME_SP_ID . ' = ' .
+                    TableConstants::TABLE_ALIAS_SP . '.' . TableConstants::TABLE_SP_COLUMN_NAME_ID
+                )
+                ->leftJoin(
+                    //'visuv',
+                    TableConstants::TABLE_ALIAS_IDP_SP_USER_VERSION,
+                    //'vds_user_version',
+                    $this->tableNameUserVersion,
+                    //'vuv',
+                    TableConstants::TABLE_ALIAS_USER_VERSION,
+                    //'visuv.user_version_id = vuv.id'
+                    TableConstants::TABLE_ALIAS_IDP_SP_USER_VERSION . '.' .
+                    TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_USER_VERSION_ID . ' = ' .
+                    TableConstants::TABLE_ALIAS_USER_VERSION . '.' . TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ID
+                )
+                ->leftJoin(
+                    //'vuv',
+                    TableConstants::TABLE_ALIAS_USER_VERSION,
+                    //'vds_user',
+                    $this->tableNameUser,
+                    //'vu',
+                    TableConstants::TABLE_ALIAS_USER,
+                    //'vuv.user_id = vu.id'
+                    TableConstants::TABLE_ALIAS_USER_VERSION . '.' .
+                    TableConstants::TABLE_USER_VERSION_COLUMN_NAME_USER_ID . ' = ' .
+                    TableConstants::TABLE_ALIAS_USER . '.' . TableConstants::TABLE_USER_COLUMN_NAME_ID
+                )
+                ->where(
+                    //'vu.identifier_hash_sha256 = ' .
+                    TableConstants::TABLE_ALIAS_USER . '.' .
+                    TableConstants::TABLE_USER_COLUMN_NAME_IDENTIFIER_HASH_SHA256 . ' = ' .
+                    $authenticationEventsQueryBuilder->createNamedParameter($userIdentifierHashSha256)
+                )
+                ->groupBy(
+                    //'vs.id'
+                    TableConstants::TABLE_ALIAS_SP . '.' . TableConstants::TABLE_SP_COLUMN_NAME_ID
+                )
+                ->orderBy(
+                    //'number_of_authentications',
+                    TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_NUMBER_OF_AUTHENTICATIONS,
+                    'DESC'
+                );
+
+
+            /** @psalm-suppress TooManyArguments */
+            $lastMetadataAndAttributesQueryBuilder->select(
+                //'vs.entity_id AS sp_entity_id',
+                TableConstants::TABLE_ALIAS_SP . '.' . TableConstants::TABLE_SP_COLUMN_NAME_ENTITY_ID . ' AS ' .
+                TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_SP_ENTITY_ID,
+                //'vsv.metadata AS sp_metadata',
+                TableConstants::TABLE_ALIAS_SP_VERSION . '.' . TableConstants::TABLE_SP_VERSION_COLUMN_NAME_METADATA .
+                ' AS ' . TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_SP_METADATA,
+                //'vuv.attributes AS user_attributes',
+                TableConstants::TABLE_ALIAS_USER_VERSION . '.' .
+                TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ATTRIBUTES . ' AS ' .
+                TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_USER_ATTRIBUTES
+                //            'vsv.id AS sp_version_id',
+                //            'vuv.id AS user_version_id',
+            )->from(
+                //'vds_authentication_event',
+                $this->tableNameAuthenticationEvent,
+                //'vae'
+                TableConstants::TABLE_ALIAS_AUTHENTICATION_EVENT
+            )
+                ->leftJoin(
+                    //'vae',
+                    TableConstants::TABLE_ALIAS_AUTHENTICATION_EVENT,
+                    //'vds_idp_sp_user_version',
+                    $this->tableNameIdpSpUserVersion,
+                    //'visuv',
+                    TableConstants::TABLE_ALIAS_IDP_SP_USER_VERSION,
+                    //'vae.idp_sp_user_version_id = visuv.id'
+                    TableConstants::TABLE_ALIAS_AUTHENTICATION_EVENT . '.' .
+                    TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_IDP_SP_USER_VERSION_ID . ' = ' .
+                    TableConstants::TABLE_ALIAS_IDP_SP_USER_VERSION . '.' .
+                    TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_ID
+                )
+                ->leftJoin(
+                    //'visuv',
+                    TableConstants::TABLE_ALIAS_IDP_SP_USER_VERSION,
+                    //'vds_sp_version',
+                    $this->tableNameSpVersion,
+                    //'vsv',
+                    TableConstants::TABLE_ALIAS_SP_VERSION,
+                    //'visuv.sp_version_id = vsv.id'
+                    TableConstants::TABLE_ALIAS_IDP_SP_USER_VERSION . '.' .
+                    TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_SP_VERSION_ID . ' = ' .
+                    TableConstants::TABLE_ALIAS_SP_VERSION . '.' . TableConstants::TABLE_SP_VERSION_COLUMN_NAME_ID
+                )
+                ->leftJoin(
+                    //'vsv',
+                    TableConstants::TABLE_ALIAS_SP_VERSION,
+                    //'vds_sp',
+                    $this->tableNameSp,
+                    //'vs',
+                    TableConstants::TABLE_ALIAS_SP,
+                    //'vsv.sp_id = vs.id'
+                    TableConstants::TABLE_ALIAS_SP_VERSION . '.' .
+                    TableConstants::TABLE_SP_VERSION_COLUMN_NAME_SP_ID . ' = ' . TableConstants::TABLE_ALIAS_SP . '.' .
+                    TableConstants::TABLE_SP_COLUMN_NAME_ID
+                )
+                ->leftJoin(
+                    //'visuv',
+                    TableConstants::TABLE_ALIAS_IDP_SP_USER_VERSION,
+                    //'vds_user_version',
+                    $this->tableNameUserVersion,
+                    //'vuv',
+                    TableConstants::TABLE_ALIAS_USER_VERSION,
+                    //'visuv.user_version_id = vuv.id'
+                    TableConstants::TABLE_ALIAS_IDP_SP_USER_VERSION . '.' .
+                    TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_USER_VERSION_ID . ' = ' .
+                    TableConstants::TABLE_ALIAS_USER_VERSION . '.' . TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ID
+                )
+                ->leftJoin(
+                    //'vuv',
+                    TableConstants::TABLE_ALIAS_USER_VERSION,
+                    //'vds_user',
+                    $this->tableNameUser,
+                    //'vu',
+                    TableConstants::TABLE_ALIAS_USER,
+                    //'vuv.user_id = vu.id'
+                    TableConstants::TABLE_ALIAS_USER_VERSION . '.' .
+                    TableConstants::TABLE_USER_VERSION_COLUMN_NAME_USER_ID . ' = ' . TableConstants::TABLE_ALIAS_USER .
+                    '.' . TableConstants::TABLE_USER_COLUMN_NAME_ID
+                )
+                ->leftJoin(
+                    //'vsv',
+                    TableConstants::TABLE_ALIAS_SP_VERSION,
+                    //'vds_sp_version',
+                    $this->tableNameSpVersion,
+                    //'vsv2',
+                    TableConstants::TABLE_ALIAS_SP_VERSION_2, // Another alias for self joining...
+                    //'vsv.id = vsv2.id AND vsv.id < vsv2.id' // To be able to get latest one...
+                    TableConstants::TABLE_ALIAS_SP_VERSION . '.' .
+                    TableConstants::TABLE_SP_VERSION_COLUMN_NAME_ID . ' = ' . TableConstants::TABLE_ALIAS_SP_VERSION_2 .
+                    '.' . TableConstants::TABLE_SP_VERSION_COLUMN_NAME_ID . ' AND ' .
+                    TableConstants::TABLE_ALIAS_SP_VERSION . '.' . TableConstants::TABLE_SP_VERSION_COLUMN_NAME_ID .
+                    ' < ' . TableConstants::TABLE_ALIAS_SP_VERSION_2 . '.' .
+                    TableConstants::TABLE_SP_VERSION_COLUMN_NAME_ID
+                )
+                ->leftJoin(
+                    //'vuv',
+                    TableConstants::TABLE_ALIAS_USER_VERSION,
+                    //'vds_user_version',
+                    $this->tableNameUserVersion,
+                    //'vuv2',
+                    TableConstants::TABLE_ALIAS_USER_VERSION_2, // Another alias for self joining...
+                    //'vuv.id = vuv2.id AND vuv.id < vuv2.id' // To be able to get latest one...
+                    TableConstants::TABLE_ALIAS_USER_VERSION . '.' .
+                    TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ID . ' = ' .
+                    TableConstants::TABLE_ALIAS_USER_VERSION_2
+                    . '.' . TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ID . ' AND ' .
+                    TableConstants::TABLE_ALIAS_USER_VERSION . '.' . TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ID .
+                    ' < ' . TableConstants::TABLE_ALIAS_USER_VERSION_2 . '.' .
+                    TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ID
+                )
+                ->where(
+                    //'vu.identifier_hash_sha256 = ' .
+                    TableConstants::TABLE_ALIAS_USER . '.' .
+                    TableConstants::TABLE_USER_COLUMN_NAME_IDENTIFIER_HASH_SHA256 . ' = ' .
+                    $lastMetadataAndAttributesQueryBuilder->createNamedParameter($userIdentifierHashSha256)
+                )
+                ->andWhere(
+                    //'vsv2.id IS NULL'
+                    TableConstants::TABLE_ALIAS_SP_VERSION_2 . '.' . TableConstants::TABLE_SP_VERSION_COLUMN_NAME_ID
+                    . ' IS NULL'
+                )
+                ->andWhere(
+                    //'vuv2.id IS NULL'
+                    TableConstants::TABLE_ALIAS_USER_VERSION_2 . '.' .
+                    TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ID . ' IS NULL'
+                );
+
+            $numberOfAuthentications = $authenticationEventsQueryBuilder->executeQuery()->fetchAllAssociativeIndexed();
+            $lastMetadataAndAttributes =
+                $lastMetadataAndAttributesQueryBuilder->executeQuery()->fetchAllAssociativeIndexed();
+
+            return array_merge_recursive($numberOfAuthentications, $lastMetadataAndAttributes);
+        } catch (\Throwable $exception) {
+            $message = sprintf(
+                'Error executing query to get connected organizations. Error was: %s.',
+                $exception->getMessage()
+            );
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function getActivity(string $userIdentifierHashSha256, int $maxResults, int $firstResult): array
+    {
+        try {
+            $authenticationEventsQueryBuilder = $this->connection->dbal()->createQueryBuilder();
+
+            /** @psalm-suppress TooManyArguments */
+            $authenticationEventsQueryBuilder->select(
+                //'vae.happened_at',
+                TableConstants::TABLE_ALIAS_AUTHENTICATION_EVENT . '.' .
+                TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_HAPPENED_AT,
+                TableConstants::TABLE_ALIAS_AUTHENTICATION_EVENT . '.' .
+                TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_CLIENT_IP_ADDRESS,
+                //'vsv.metadata AS sp_metadata',
+                TableConstants::TABLE_ALIAS_SP_VERSION . '.' . TableConstants::TABLE_SP_VERSION_COLUMN_NAME_METADATA .
+                ' AS ' . TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_SP_METADATA,
+                //'vuv.attributes AS user_attributes'
+                TableConstants::TABLE_ALIAS_USER_VERSION . '.' .
+                TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ATTRIBUTES . ' AS ' .
+                TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_USER_ATTRIBUTES
+            )->from(
+                //'vds_authentication_event', 'vae'
+                $this->tableNameAuthenticationEvent,
+                //'vae'
+                TableConstants::TABLE_ALIAS_AUTHENTICATION_EVENT
+            )
+                ->leftJoin(
+                    //'vae',
+                    TableConstants::TABLE_ALIAS_AUTHENTICATION_EVENT,
+                    //'vds_idp_sp_user_version',
+                    $this->tableNameIdpSpUserVersion,
+                    //'visuv',
+                    TableConstants::TABLE_ALIAS_IDP_SP_USER_VERSION,
+                    //'vae.idp_sp_user_version_id = visuv.id'
+                    TableConstants::TABLE_ALIAS_AUTHENTICATION_EVENT . '.' .
+                    TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_IDP_SP_USER_VERSION_ID . ' = ' .
+                    TableConstants::TABLE_ALIAS_IDP_SP_USER_VERSION . '.' .
+                    TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_ID
+                )
+                ->leftJoin(
+                    //'visuv',
+                    TableConstants::TABLE_ALIAS_IDP_SP_USER_VERSION,
+                    //'vds_sp_version',
+                    $this->tableNameSpVersion,
+                    //'vsv',
+                    TableConstants::TABLE_ALIAS_SP_VERSION,
+                    //'visuv.sp_version_id = vsv.id'
+                    TableConstants::TABLE_ALIAS_IDP_SP_USER_VERSION . '.' .
+                    TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_SP_VERSION_ID . ' = ' .
+                    TableConstants::TABLE_ALIAS_SP_VERSION . '.' . TableConstants::TABLE_SP_VERSION_COLUMN_NAME_ID
+                )
+                ->leftJoin(
+                    //'vsv',
+                    TableConstants::TABLE_ALIAS_SP_VERSION,
+                    //'vds_sp',
+                    $this->tableNameSp,
+                    //'vs',
+                    TableConstants::TABLE_ALIAS_SP,
+                    //'vsv.sp_id = vs.id'
+                    TableConstants::TABLE_ALIAS_SP_VERSION . '.' . TableConstants::TABLE_SP_VERSION_COLUMN_NAME_SP_ID .
+                    ' = ' . TableConstants::TABLE_ALIAS_SP . '.' . TableConstants::TABLE_SP_COLUMN_NAME_ID
+                )
+                ->leftJoin(
+                    //'visuv',
+                    TableConstants::TABLE_ALIAS_IDP_SP_USER_VERSION,
+                    //'vds_user_version',
+                    $this->tableNameUserVersion,
+                    //'vuv',
+                    TableConstants::TABLE_ALIAS_USER_VERSION,
+                    //'visuv.user_version_id = vuv.id'
+                    TableConstants::TABLE_ALIAS_IDP_SP_USER_VERSION . '.' .
+                    TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_USER_VERSION_ID . ' = ' .
+                    TableConstants::TABLE_ALIAS_USER_VERSION . '.' . TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ID
+                )
+                ->leftJoin(
+                    //'vuv',
+                    TableConstants::TABLE_ALIAS_USER_VERSION,
+                    //'vds_user',
+                    $this->tableNameUser,
+                    //'vu',
+                    TableConstants::TABLE_ALIAS_USER,
+                    //'vuv.user_id = vu.id'
+                    TableConstants::TABLE_ALIAS_USER_VERSION . '.' .
+                    TableConstants::TABLE_USER_VERSION_COLUMN_NAME_USER_ID . ' = ' . TableConstants::TABLE_ALIAS_USER .
+                    '.' . TableConstants::TABLE_USER_COLUMN_NAME_ID
+                )
+                ->where(
+                    //'vu.identifier_hash_sha256 = ' .
+                    TableConstants::TABLE_ALIAS_USER . '.' .
+                    TableConstants::TABLE_USER_COLUMN_NAME_IDENTIFIER_HASH_SHA256 . ' = ' .
+                    $authenticationEventsQueryBuilder->createNamedParameter($userIdentifierHashSha256)
+                )
+                ->orderBy(
+                //'vae.id',
+                    TableConstants::TABLE_ALIAS_AUTHENTICATION_EVENT . '.' .
+                    TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_ID,
+                    'DESC'
+                )
+            ->setMaxResults($maxResults)
+            ->setFirstResult($firstResult);
+
+            return $authenticationEventsQueryBuilder->executeQuery()->fetchAllAssociative();
+        } catch (\Throwable $exception) {
+            $message = sprintf(
+                'Error executing query to get connected organizations. Error was: %s.',
+                $exception->getMessage()
+            );
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function deleteAuthenticationEventsOlderThan(\DateTimeImmutable $dateTime): void
+    {
+        try {
+            $queryBuilder = $this->connection->dbal()->createQueryBuilder();
+
+            $queryBuilder->delete($this->tableNameAuthenticationEvent)
+                ->where(
+                    $queryBuilder->expr()->lt(
+                        TableConstants::TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_HAPPENED_AT,
+                        $queryBuilder->createNamedParameter($dateTime, Types::DATETIME_IMMUTABLE)
+                    )
+                )->executeStatement();
+        } catch (Throwable $exception) {
+            $message = sprintf(
+                'Error executing query to delete old authentication events. Error was: %s.',
+                $exception->getMessage()
+            );
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+}
diff --git a/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/TableConstants.php b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/TableConstants.php
new file mode 100644
index 0000000..532a8c7
--- /dev/null
+++ b/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/TableConstants.php
@@ -0,0 +1,102 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store;
+
+class TableConstants
+{
+    public const TABLE_PREFIX = 'vds_'; // versioned data store
+
+    // Any SAML entity ID should have maximum 1024 chars per
+    // https://stackoverflow.com/questions/24196369/what-to-present-at-saml-entityid-url
+    public const COLUMN_ENTITY_ID_LENGTH = 1024;
+    public const COLUMN_HASH_SHA265_HEXITS_LENGTH = 64;
+    public const COLUMN_IP_ADDRESS_LENGTH = 45;
+
+
+    // Table 'idp'
+    public const TABLE_NAME_IDP = 'idp';
+    public const TABLE_ALIAS_IDP = self::TABLE_PREFIX . 'i';
+    public const TABLE_IDP_COLUMN_NAME_ID = 'id'; // int
+    public const TABLE_IDP_COLUMN_NAME_ENTITY_ID = 'entity_id'; // Entity ID value, string, varchar(1024)
+    public const TABLE_IDP_COLUMN_NAME_ENTITY_ID_HASH_SHA256 = 'entity_id_hash_sha256'; // ha256 hash hexits, char(64)
+    public const TABLE_IDP_COLUMN_NAME_CREATED_AT = 'created_at'; // First time IdP usage, datetime
+
+    // Table 'idp_version'
+    public const TABLE_NAME_IDP_VERSION = 'idp_version';
+    public const TABLE_ALIAS_IDP_VERSION = self::TABLE_PREFIX . 'iv';
+    public const TABLE_IDP_VERSION_COLUMN_NAME_ID = 'id'; // int ID
+    public const TABLE_IDP_VERSION_COLUMN_NAME_IDP_ID = 'idp_id'; // FK
+    public const TABLE_IDP_VERSION_COLUMN_NAME_METADATA = 'metadata'; // Serialized IdP metadata version
+    public const TABLE_IDP_VERSION_COLUMN_NAME_METADATA_HASH_SHA256 = 'metadata_hash_sha256'; // Metadata sha256 hash
+    public const TABLE_IDP_VERSION_COLUMN_NAME_CREATED_AT = 'created_at';
+
+    // Table 'sp', same structure as in 'idp'
+    public const TABLE_NAME_SP = 'sp';
+    public const TABLE_ALIAS_SP = self::TABLE_PREFIX . 's';
+    public const TABLE_SP_COLUMN_NAME_ID = 'id';
+    public const TABLE_SP_COLUMN_NAME_ENTITY_ID = 'entity_id';
+    public const TABLE_SP_COLUMN_NAME_ENTITY_ID_HASH_SHA256 = 'entity_id_hash_sha256';
+    public const TABLE_SP_COLUMN_NAME_CREATED_AT = 'created_at';
+
+    // Table 'sp_version', same structure as in 'idp_version'
+    public const TABLE_NAME_SP_VERSION = 'sp_version';
+    public const TABLE_ALIAS_SP_VERSION = self::TABLE_PREFIX . 'sv';
+    public const TABLE_ALIAS_SP_VERSION_2 = self::TABLE_ALIAS_SP_VERSION . '_2';
+    public const TABLE_SP_VERSION_COLUMN_NAME_ID = 'id';
+    public const TABLE_SP_VERSION_COLUMN_NAME_SP_ID = 'sp_id';
+    public const TABLE_SP_VERSION_COLUMN_NAME_METADATA = 'metadata';
+    public const TABLE_SP_VERSION_COLUMN_NAME_METADATA_HASH_SHA256 = 'metadata_hash_sha256';
+    public const TABLE_SP_VERSION_COLUMN_NAME_CREATED_AT = 'created_at';
+
+    // Table 'user'
+    public const TABLE_NAME_USER = 'user';
+    public const TABLE_ALIAS_USER = self::TABLE_PREFIX . 'u';
+    public const TABLE_USER_COLUMN_NAME_ID = 'id'; // int
+    public const TABLE_USER_COLUMN_NAME_IDENTIFIER = 'identifier'; // text, varies... (can be ePTID, which is long XML).
+    public const TABLE_USER_COLUMN_NAME_IDENTIFIER_HASH_SHA256 = 'identifier_hash_sha256';
+    public const TABLE_USER_COLUMN_NAME_CREATED_AT = 'created_at';
+
+    // Table 'user_version' (versioned attributes)
+    public const TABLE_NAME_USER_VERSION = 'user_version';
+    public const TABLE_ALIAS_USER_VERSION = self::TABLE_PREFIX . 'uv';
+    public const TABLE_ALIAS_USER_VERSION_2 = self::TABLE_ALIAS_USER_VERSION . '_2';
+    public const TABLE_USER_VERSION_COLUMN_NAME_ID = 'id'; // int ID
+    public const TABLE_USER_VERSION_COLUMN_NAME_USER_ID = 'user_id'; // FK
+    public const TABLE_USER_VERSION_COLUMN_NAME_ATTRIBUTES = 'attributes'; // Serialized attributes version
+    public const TABLE_USER_VERSION_COLUMN_NAME_ATTRIBUTES_HASH_SHA256 = 'attributes_hash_sha256';
+    public const TABLE_USER_VERSION_COLUMN_NAME_CREATED_AT = 'created_at';
+
+    // Attribute versions released to SP version
+    public const TABLE_NAME_IDP_SP_USER_VERSION = 'idp_sp_user_version';
+    public const TABLE_ALIAS_IDP_SP_USER_VERSION = self::TABLE_PREFIX . 'isuv';
+    public const TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_ID = 'id';
+    public const TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_IDP_VERSION_ID = 'idp_version_id';
+    public const TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_SP_VERSION_ID = 'sp_version_id';
+    public const TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_USER_VERSION_ID = 'user_version_id';
+    public const TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_CREATED_AT = 'created_at';
+
+    // Table 'authentication_event'.
+    public const TABLE_NAME_AUTHENTICATION_EVENT = 'authentication_event';
+    public const TABLE_ALIAS_AUTHENTICATION_EVENT = self::TABLE_PREFIX . 'ae';
+    public const TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_ID = 'id';
+    public const TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_IDP_SP_USER_VERSION_ID = 'idp_sp_user_version_id';
+    public const TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_HAPPENED_AT = 'happened_at';
+    public const TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_CLIENT_IP_ADDRESS = 'client_ip_address';
+    public const TABLE_AUTHENTICATION_EVENT_COLUMN_NAME_CREATED_AT = 'created_at';
+
+    // Entity 'ConnectedOrganization' (service provider) related.
+    public const ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_SP_ENTITY_ID = 'sp_entity_id';
+    public const ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_NUMBER_OF_AUTHENTICATIONS = 'number_of_authentications';
+    public const ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_LAST_AUTHENTICATION_AT = 'last_authentication_at';
+    public const ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_FIRST_AUTHENTICATION_AT = 'first_authentication_at';
+    public const ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_SP_METADATA = 'sp_metadata';
+    public const ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_USER_ATTRIBUTES = 'user_attributes';
+
+    // Entity 'Activity' related.
+    public const ENTITY_ACTIVITY_COLUMN_NAME_SP_METADATA = 'sp_metadata';
+    public const ENTITY_ACTIVITY_COLUMN_NAME_USER_ATTRIBUTES = 'user_attributes';
+    public const ENTITY_ACTIVITY_COLUMN_NAME_HAPPENED_AT = 'happened_at';
+    public const ENTITY_ACTIVITY_COLUMN_NAME_CLIENT_IP_ADDRESS = 'client_ip_address';
+}
diff --git a/src/Stores/Interfaces/ConnectionInterface.php b/src/Stores/Interfaces/ConnectionInterface.php
new file mode 100644
index 0000000..b61d320
--- /dev/null
+++ b/src/Stores/Interfaces/ConnectionInterface.php
@@ -0,0 +1,9 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Interfaces;
+
+interface ConnectionInterface
+{
+}
diff --git a/src/Stores/Interfaces/DataStoreInterface.php b/src/Stores/Interfaces/DataStoreInterface.php
new file mode 100644
index 0000000..6fefe9a
--- /dev/null
+++ b/src/Stores/Interfaces/DataStoreInterface.php
@@ -0,0 +1,29 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Interfaces;
+
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event;
+use SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider;
+use SimpleSAML\Module\accounting\Entities\Activity;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+
+interface DataStoreInterface extends StoreInterface
+{
+    public static function build(
+        ModuleConfiguration $moduleConfiguration,
+        LoggerInterface $logger,
+        string $connectionKey = null,
+        string $connectionType = ModuleConfiguration\ConnectionType::MASTER
+    ): self;
+
+    public function persist(Event $authenticationEvent): void;
+
+    public function getConnectedOrganizations(string $userIdentifierHashSha256): ConnectedServiceProvider\Bag;
+
+    public function getActivity(string $userIdentifierHashSha256, int $maxResults, int $firstResult): Activity\Bag;
+
+    public function deleteDataOlderThan(\DateTimeImmutable $dateTime): void;
+}
diff --git a/src/Stores/Interfaces/JobsStoreInterface.php b/src/Stores/Interfaces/JobsStoreInterface.php
new file mode 100644
index 0000000..43f9bdb
--- /dev/null
+++ b/src/Stores/Interfaces/JobsStoreInterface.php
@@ -0,0 +1,38 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Interfaces;
+
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Module\accounting\Entities\Interfaces\JobInterface;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+
+interface JobsStoreInterface extends StoreInterface
+{
+    public static function build(
+        ModuleConfiguration $moduleConfiguration,
+        LoggerInterface $logger,
+        string $connectionKey = null
+    ): self;
+
+    /**
+     * Add job to queue
+     * @param JobInterface $job
+     * @return void
+     */
+    public function enqueue(JobInterface $job): void;
+
+    /**
+     * Get job from queue
+     * @param string $type Type of the job, typically FQ class name of job object.
+     * @return ?JobInterface
+     */
+    public function dequeue(string $type): ?JobInterface;
+
+    /**
+     * @param JobInterface $job
+     * @return void
+     */
+    public function markFailedJob(JobInterface $job): void;
+}
diff --git a/src/Stores/Interfaces/MigrationInterface.php b/src/Stores/Interfaces/MigrationInterface.php
new file mode 100644
index 0000000..ce7e523
--- /dev/null
+++ b/src/Stores/Interfaces/MigrationInterface.php
@@ -0,0 +1,22 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Interfaces;
+
+interface MigrationInterface
+{
+    /**
+     * Run migration forward.
+     *
+     * @return void
+     */
+    public function run(): void;
+
+    /**
+     * Run migration backward.
+     *
+     * @return void
+     */
+    public function revert(): void;
+}
diff --git a/src/Stores/Interfaces/StoreInterface.php b/src/Stores/Interfaces/StoreInterface.php
new file mode 100644
index 0000000..29b1bd0
--- /dev/null
+++ b/src/Stores/Interfaces/StoreInterface.php
@@ -0,0 +1,19 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Interfaces;
+
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Module\accounting\Interfaces\BuildableUsingModuleConfigurationInterface;
+use SimpleSAML\Module\accounting\Interfaces\SetupableInterface;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+
+interface StoreInterface extends BuildableUsingModuleConfigurationInterface, SetupableInterface
+{
+    public static function build(
+        ModuleConfiguration $moduleConfiguration,
+        LoggerInterface $logger,
+        string $connectionKey = null
+    ): self;
+}
diff --git a/src/Stores/Jobs/DoctrineDbal/Store.php b/src/Stores/Jobs/DoctrineDbal/Store.php
new file mode 100644
index 0000000..86107ec
--- /dev/null
+++ b/src/Stores/Jobs/DoctrineDbal/Store.php
@@ -0,0 +1,153 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal;
+
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Module\accounting\Entities\Interfaces\JobInterface;
+use SimpleSAML\Module\accounting\Exceptions\StoreException;
+use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractStore;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Factory;
+use SimpleSAML\Module\accounting\Stores\Interfaces\JobsStoreInterface;
+use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Repository;
+use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\TableConstants;
+use Throwable;
+
+class Store extends AbstractStore implements JobsStoreInterface
+{
+    protected string $prefixedTableNameJobs;
+    protected string $prefixedTableNameFailedJobs;
+    protected Repository $jobsRepository;
+    protected Repository $failedJobsRepository;
+
+    /**
+     * @throws StoreException
+     */
+    public function __construct(
+        ModuleConfiguration $moduleConfiguration,
+        LoggerInterface $logger,
+        string $connectionKey = null,
+        string $connectionType = ModuleConfiguration\ConnectionType::MASTER,
+        Factory $connectionFactory = null,
+        Repository $jobsRepository = null,
+        Repository $failedJobsRepository = null
+    ) {
+        parent::__construct($moduleConfiguration, $logger, $connectionKey, $connectionType, $connectionFactory);
+
+        $this->prefixedTableNameJobs = $this->connection->preparePrefixedTableName(TableConstants::TABLE_NAME_JOB);
+        $this->prefixedTableNameFailedJobs = $this->connection
+            ->preparePrefixedTableName(TableConstants::TABLE_NAME_JOB_FAILED);
+
+        $this->jobsRepository = $jobsRepository ??
+            new Repository($this->connection, $this->prefixedTableNameJobs, $this->logger);
+
+        $this->failedJobsRepository = $failedJobsRepository ??
+            new Repository($this->connection, $this->prefixedTableNameFailedJobs, $this->logger);
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function enqueue(JobInterface $job): void
+    {
+        $this->jobsRepository->insert($job);
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function dequeue(string $type): ?JobInterface
+    {
+        /** @noinspection PhpUnusedLocalVariableInspection - psalm reports possibly undefined variable */
+        $job = null;
+        $attempts = 0;
+        $maxDeleteAttempts = 3;
+        $this->connection->dbal()->getTransactionIsolation();
+
+        // Do the dequeue without using transactions, since the underlying database engine might not support it
+        // (for example, MyISAM engine in MySQL database).
+        try {
+            // Check if there are any jobs in the store...
+            while (($job = $this->jobsRepository->getNext($type)) !== null) {
+                // We have job instance.
+                $jobId = $job->getId();
+
+                if ($jobId === null) {
+                    throw new UnexpectedValueException('Retrieved job does not contain ID.');
+                }
+
+                $attempts++;
+
+                // Let's try to delete this job from the store, so it can't be fetched again.
+                if ($this->jobsRepository->delete($jobId) === false) {
+                    // It seems that this job has already been deleted in the meantime.
+                    // Check if this happened before. If threshold is reached, throw.
+                    // Otherwise, try to get next job again.
+                    $message = sprintf(
+                        'Job retrieval was successful, however it was deleted in the meantime. Attempt: %s',
+                        $attempts
+                    );
+                    $this->logger->warning($message, ['jobId' => $jobId]);
+                    if ($attempts > $maxDeleteAttempts) {
+                        throw new StoreException($message);
+                    }
+
+                    continue;
+                }
+
+                // We have found and dequeued a job, so finish with the search.
+                break;
+            }
+        } catch (Throwable $exception) {
+            throw new StoreException(
+                'Error while trying to dequeue a job.',
+                (int)$exception->getCode(),
+                $exception
+            );
+        }
+
+        return $job;
+    }
+
+    public function getPrefixedTableNameJobs(): string
+    {
+        return $this->prefixedTableNameJobs;
+    }
+
+    public function getPrefixedTableNameFailedJobs(): string
+    {
+        return $this->prefixedTableNameFailedJobs;
+    }
+
+    /**
+     * Build store instance.
+     * @param ModuleConfiguration $moduleConfiguration
+     * @param LoggerInterface $logger
+     * @param string|null $connectionKey
+     * @param string $connectionType
+     * @return self
+     * @throws StoreException
+     */
+    public static function build(
+        ModuleConfiguration $moduleConfiguration,
+        LoggerInterface $logger,
+        string $connectionKey = null
+    ): self {
+        return new self(
+            $moduleConfiguration,
+            $logger,
+            $connectionKey
+        );
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function markFailedJob(JobInterface $job): void
+    {
+        $this->failedJobsRepository->insert($job);
+    }
+}
diff --git a/src/Stores/Jobs/DoctrineDbal/Store/Migrations/Bases/AbstractCreateJobsTable.php b/src/Stores/Jobs/DoctrineDbal/Store/Migrations/Bases/AbstractCreateJobsTable.php
new file mode 100644
index 0000000..203afb8
--- /dev/null
+++ b/src/Stores/Jobs/DoctrineDbal/Store/Migrations/Bases/AbstractCreateJobsTable.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Bases;
+
+use Doctrine\DBAL\Schema\Table;
+use Doctrine\DBAL\Types\Types;
+use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration;
+use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\TableConstants;
+use Throwable;
+
+abstract class AbstractCreateJobsTable extends AbstractMigration
+{
+    /**
+     * @throws MigrationException
+     */
+    public function run(): void
+    {
+        $tableName = $this->preparePrefixedTableName($this->getJobsTableName());
+
+        try {
+            $table = new Table($tableName);
+
+            $table->addColumn('id', Types::BIGINT)
+                ->setUnsigned(true)
+                ->setAutoincrement(true);
+
+            $table->addColumn('type', Types::STRING)
+                ->setLength(TableConstants::COLUMN_TYPE_LENGTH);
+
+            $table->addColumn('payload', Types::TEXT);
+            $table->addColumn('created_at', Types::DATETIMETZ_IMMUTABLE);
+
+            $table->setPrimaryKey(['id']);
+
+            $this->schemaManager->createTable($table);
+        } catch (Throwable $exception) {
+            throw $this->prepareGenericMigrationException(
+                \sprintf('Could not create table %s.', $tableName),
+                $exception
+            );
+        }
+    }
+
+    /**
+     * @throws MigrationException
+     */
+    public function revert(): void
+    {
+        $tableName = $this->preparePrefixedTableName($this->getJobsTableName());
+
+        try {
+            $this->schemaManager->dropTable($tableName);
+        } catch (Throwable $exception) {
+            throw $this->prepareGenericMigrationException(\sprintf('Could not drop table %s.', $tableName), $exception);
+        }
+    }
+
+    abstract protected function getJobsTableName(): string;
+}
diff --git a/src/Stores/Jobs/DoctrineDbal/Store/Migrations/Version20220601000000CreateJobTable.php b/src/Stores/Jobs/DoctrineDbal/Store/Migrations/Version20220601000000CreateJobTable.php
new file mode 100644
index 0000000..838b202
--- /dev/null
+++ b/src/Stores/Jobs/DoctrineDbal/Store/Migrations/Version20220601000000CreateJobTable.php
@@ -0,0 +1,15 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations;
+
+use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store;
+
+class Version20220601000000CreateJobTable extends Store\Migrations\Bases\AbstractCreateJobsTable
+{
+    protected function getJobsTableName(): string
+    {
+        return 'job';
+    }
+}
diff --git a/src/Stores/Jobs/DoctrineDbal/Store/Migrations/Version20220601000100CreateJobFailedTable.php b/src/Stores/Jobs/DoctrineDbal/Store/Migrations/Version20220601000100CreateJobFailedTable.php
new file mode 100644
index 0000000..9aa852d
--- /dev/null
+++ b/src/Stores/Jobs/DoctrineDbal/Store/Migrations/Version20220601000100CreateJobFailedTable.php
@@ -0,0 +1,15 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations;
+
+use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store;
+
+class Version20220601000100CreateJobFailedTable extends Store\Migrations\Bases\AbstractCreateJobsTable
+{
+    protected function getJobsTableName(): string
+    {
+        return 'job_failed';
+    }
+}
diff --git a/src/Stores/Jobs/DoctrineDbal/Store/RawJob.php b/src/Stores/Jobs/DoctrineDbal/Store/RawJob.php
new file mode 100644
index 0000000..5737b92
--- /dev/null
+++ b/src/Stores/Jobs/DoctrineDbal/Store/RawJob.php
@@ -0,0 +1,119 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store;
+
+use DateTimeImmutable;
+use Doctrine\DBAL\Platforms\AbstractPlatform;
+use Doctrine\DBAL\Types\Type;
+use Doctrine\DBAL\Types\Types;
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload;
+use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+use SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractRawEntity;
+use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store;
+use Throwable;
+
+use function sprintf;
+
+class RawJob extends AbstractRawEntity
+{
+    protected int $id;
+    protected AbstractPayload $payload;
+    protected string $type;
+    protected DateTimeImmutable $createdAt;
+
+    public function __construct(array $rawRow, AbstractPlatform $abstractPlatform)
+    {
+        parent::__construct($rawRow, $abstractPlatform);
+
+        $this->id = (int)$rawRow[Store\TableConstants::COLUMN_NAME_ID];
+        $this->payload = $this->resolvePayload((string)$rawRow[Store\TableConstants::COLUMN_NAME_PAYLOAD]);
+        $this->type = (string)$rawRow[Store\TableConstants::COLUMN_NAME_TYPE];
+        $this->createdAt = $this->resolveDateTimeImmutable($rawRow[Store\TableConstants::COLUMN_NAME_CREATED_AT]);
+    }
+
+    protected function validate(array $rawRow): void
+    {
+        $columnsToCheck = [
+            Store\TableConstants::COLUMN_NAME_ID,
+            Store\TableConstants::COLUMN_NAME_PAYLOAD,
+            Store\TableConstants::COLUMN_NAME_TYPE,
+            Store\TableConstants::COLUMN_NAME_CREATED_AT,
+        ];
+
+        foreach ($columnsToCheck as $column) {
+            if (empty($rawRow[$column])) {
+                throw new UnexpectedValueException(sprintf('Column %s must be set.', $column));
+            }
+        }
+
+        if (! is_numeric($rawRow[Store\TableConstants::COLUMN_NAME_ID])) {
+            throw new UnexpectedValueException(
+                sprintf('Column %s must be numeric.', Store\TableConstants::COLUMN_NAME_ID)
+            );
+        }
+
+        if (! is_string($rawRow[Store\TableConstants::COLUMN_NAME_PAYLOAD])) {
+            throw new UnexpectedValueException(
+                sprintf('Column %s must be string.', Store\TableConstants::COLUMN_NAME_PAYLOAD)
+            );
+        }
+
+        if (! is_string($rawRow[Store\TableConstants::COLUMN_NAME_TYPE])) {
+            throw new UnexpectedValueException(
+                sprintf('Column %s must be string.', Store\TableConstants::COLUMN_NAME_TYPE)
+            );
+        }
+
+        if (! is_string($rawRow[Store\TableConstants::COLUMN_NAME_CREATED_AT])) {
+            throw new UnexpectedValueException(
+                sprintf('Column %s must be string.', Store\TableConstants::COLUMN_NAME_CREATED_AT)
+            );
+        }
+    }
+
+    protected function resolvePayload(string $rawPayload): AbstractPayload
+    {
+        /** @psalm-suppress MixedAssignment - we check the type manually */
+        $payload = unserialize($rawPayload);
+
+        if ($payload instanceof AbstractPayload) {
+            return $payload;
+        }
+
+        throw new UnexpectedValueException('Job payload is not instance of AbstractPayload.');
+    }
+
+    /**
+     * @return int
+     */
+    public function getId(): int
+    {
+        return $this->id;
+    }
+
+    /**
+     * @return AbstractPayload
+     */
+    public function getPayload(): AbstractPayload
+    {
+        return $this->payload;
+    }
+
+    /**
+     * @return string
+     */
+    public function getType(): string
+    {
+        return $this->type;
+    }
+
+    /**
+     * @return DateTimeImmutable
+     */
+    public function getCreatedAt(): DateTimeImmutable
+    {
+        return $this->createdAt;
+    }
+}
diff --git a/src/Stores/Jobs/DoctrineDbal/Store/Repository.php b/src/Stores/Jobs/DoctrineDbal/Store/Repository.php
new file mode 100644
index 0000000..ac983a7
--- /dev/null
+++ b/src/Stores/Jobs/DoctrineDbal/Store/Repository.php
@@ -0,0 +1,194 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store;
+
+use Doctrine\DBAL\Types\Types;
+use Psr\Log\LoggerInterface;
+use ReflectionClass;
+use SimpleSAML\Module\accounting\Entities\GenericJob;
+use SimpleSAML\Module\accounting\Entities\Interfaces\JobInterface;
+use SimpleSAML\Module\accounting\Exceptions\StoreException;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection;
+use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store;
+use Throwable;
+
+class Repository
+{
+    protected Connection $connection;
+
+    protected array $validJobsTableNames = [];
+
+    protected string $tableName;
+    protected LoggerInterface $logger;
+
+    /**
+     * @throws StoreException
+     */
+    public function __construct(Connection $connection, string $tableName, LoggerInterface $logger)
+    {
+        $this->connection = $connection;
+
+        $this->prepareValidJobsTableNames();
+
+        $this->validateTableName($tableName);
+
+        $this->tableName = $tableName;
+        $this->logger = $logger;
+    }
+
+    protected function prepareValidJobsTableNames(): void
+    {
+        $this->validJobsTableNames[] = $this->connection
+            ->preparePrefixedTableName(Store\TableConstants::TABLE_NAME_JOB);
+        $this->validJobsTableNames[] = $this->connection
+            ->preparePrefixedTableName(Store\TableConstants::TABLE_NAME_JOB_FAILED);
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function insert(JobInterface $job): void
+    {
+        $this->validateType($job->getType());
+
+        $queryBuilder = $this->connection->dbal()->createQueryBuilder();
+
+        $queryBuilder->insert($this->tableName)
+            ->values(
+                [
+                    Store\TableConstants::COLUMN_NAME_PAYLOAD => ':' . Store\TableConstants::COLUMN_NAME_PAYLOAD,
+                    Store\TableConstants::COLUMN_NAME_TYPE => ':' . Store\TableConstants::COLUMN_NAME_TYPE,
+                    Store\TableConstants::COLUMN_NAME_CREATED_AT => ':' . Store\TableConstants::COLUMN_NAME_CREATED_AT,
+                ]
+            )
+            ->setParameters(
+                [
+                    Store\TableConstants::COLUMN_NAME_PAYLOAD => serialize($job->getPayload()),
+                    Store\TableConstants::COLUMN_NAME_TYPE => $job->getType(),
+                    Store\TableConstants::COLUMN_NAME_CREATED_AT => $job->getCreatedAt(),
+                ],
+                [
+                    Store\TableConstants::COLUMN_NAME_PAYLOAD => Types::TEXT,
+                    Store\TableConstants::COLUMN_NAME_TYPE => Types::STRING,
+                    Store\TableConstants::COLUMN_NAME_CREATED_AT => Types::DATETIMETZ_IMMUTABLE
+                ]
+            );
+
+        try {
+            $queryBuilder->executeStatement();
+        } catch (Throwable $exception) {
+            $message = sprintf('Could not insert job (%s)', $exception->getMessage());
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @param string|null $type
+     * @return ?JobInterface
+     * @throws StoreException
+     */
+    public function getNext(string $type = null): ?JobInterface
+    {
+        $queryBuilder = $this->connection->dbal()->createQueryBuilder();
+
+        /**
+         * @psalm-suppress TooManyArguments - providing array or null is deprecated
+         */
+        $queryBuilder->select(
+            Store\TableConstants::COLUMN_NAME_ID,
+            Store\TableConstants::COLUMN_NAME_PAYLOAD,
+            Store\TableConstants::COLUMN_NAME_TYPE,
+            Store\TableConstants::COLUMN_NAME_CREATED_AT
+        )
+            ->from($this->tableName)
+            ->orderBy(Store\TableConstants::COLUMN_NAME_ID)
+            ->setMaxResults(1);
+
+        if ($type !== null) {
+            $queryBuilder->where(
+                Store\TableConstants::COLUMN_NAME_TYPE . ' = ' . $queryBuilder->createNamedParameter($type)
+            );
+        }
+
+        try {
+            $result = $queryBuilder->executeQuery();
+            $row = $result->fetchAssociative();
+        } catch (Throwable $exception) {
+            $message = 'Error while trying to execute query to get next available job.';
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+
+        if ($row === false) {
+            return null;
+        }
+
+        try {
+            $rawJob = new RawJob($row, $this->connection->dbal()->getDatabasePlatform());
+            $rawJobType = $rawJob->getType();
+
+            // Try to create a specific job type. Otherwise, create a generic one.
+            if (class_exists($rawJobType) && is_subclass_of($rawJobType, JobInterface::class)) {
+                $job = (new ReflectionClass($rawJobType))
+                    ->newInstance($rawJob->getPayload(), $rawJob->getId(), $rawJob->getCreatedAt());
+            } else {
+                // No (valid) job type, so generic one will do...
+                $job = new GenericJob($rawJob->getPayload(), $rawJob->getId(), $rawJob->getCreatedAt());
+            }
+        } catch (Throwable $exception) {
+            $message = 'Could not create a job instance.';
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+
+        return $job;
+    }
+
+    /**
+     * @throws StoreException
+     */
+    public function delete(int $id): bool
+    {
+        try {
+            $numberOfAffectedRows = (int)$this->connection->dbal()
+                ->delete(
+                    $this->tableName,
+                    [Store\TableConstants::COLUMN_NAME_ID => $id],
+                    [Store\TableConstants::COLUMN_NAME_ID => Types::BIGINT]
+                );
+        } catch (Throwable $exception) {
+            $message = sprintf('Error while trying to delete a job with ID %s.', $id);
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+
+        if ($numberOfAffectedRows === 0) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * @throws StoreException
+     */
+    protected function validateTableName(string $tableName): void
+    {
+        if (!in_array($tableName, $this->validJobsTableNames)) {
+            throw new StoreException(
+                sprintf('Table %s is not valid table for storing jobs.', $tableName)
+            );
+        }
+    }
+
+    /**
+     * @throws StoreException
+     */
+    protected function validateType(string $type): void
+    {
+        if (mb_strlen($type) > Store\TableConstants::COLUMN_TYPE_LENGTH) {
+            throw new StoreException(
+                sprintf('String length for type column exceeds %s limit.', Store\TableConstants::COLUMN_TYPE_LENGTH)
+            );
+        }
+    }
+}
diff --git a/src/Stores/Jobs/DoctrineDbal/Store/TableConstants.php b/src/Stores/Jobs/DoctrineDbal/Store/TableConstants.php
new file mode 100644
index 0000000..55f1779
--- /dev/null
+++ b/src/Stores/Jobs/DoctrineDbal/Store/TableConstants.php
@@ -0,0 +1,19 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store;
+
+class TableConstants
+{
+    public const TABLE_NAME_JOB = 'job';
+    public const TABLE_NAME_JOB_FAILED = 'job_failed';
+
+    // Both tables have same columns.
+    public const COLUMN_NAME_ID = 'id';
+    public const COLUMN_NAME_PAYLOAD = 'payload';
+    public const COLUMN_NAME_TYPE = 'type';
+    public const COLUMN_NAME_CREATED_AT = 'created_at';
+
+    public const COLUMN_TYPE_LENGTH = 1024;
+}
diff --git a/src/Stores/Jobs/PhpRedis/RedisStore.php b/src/Stores/Jobs/PhpRedis/RedisStore.php
new file mode 100644
index 0000000..20e6003
--- /dev/null
+++ b/src/Stores/Jobs/PhpRedis/RedisStore.php
@@ -0,0 +1,190 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Stores\Jobs\PhpRedis;
+
+use Psr\Log\LoggerInterface;
+use Redis;
+use SimpleSAML\Module\accounting\Entities\Interfaces\JobInterface;
+use SimpleSAML\Module\accounting\Exceptions\InvalidConfigurationException;
+use SimpleSAML\Module\accounting\Exceptions\StoreException;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Stores\Bases\AbstractStore;
+use SimpleSAML\Module\accounting\Stores\Interfaces\JobsStoreInterface;
+use Throwable;
+
+class RedisStore extends AbstractStore implements JobsStoreInterface
+{
+    public const LIST_KEY_JOB = 'job';
+    public const LIST_KEY_JOB_FAILED = 'job_failed';
+
+    protected Redis $redis;
+
+    /**
+     * @throws StoreException
+     */
+    public function __construct(
+        ModuleConfiguration $moduleConfiguration,
+        LoggerInterface $logger,
+        string $connectionKey = null,
+        string $connectionType = ModuleConfiguration\ConnectionType::MASTER,
+        Redis $redis = null
+    ) {
+        parent::__construct($moduleConfiguration, $logger, $connectionKey, $connectionType);
+        $this->redis = $redis ?? new Redis();
+        $connectionParameters = $this->getConnectionParameters();
+
+        try {
+            if (!$this->redis->isConnected()) {
+                $this->redis->connect(
+                    (string)($connectionParameters['host'] ?? ''),
+                    (int)($connectionParameters['port'] ?? 6379),
+                    (float)($connectionParameters['connectTimeout'] ?? 0.0),
+                    null,
+                    (int)($connectionParameters['retryInterval'] ?? 0),
+                    (int)($connectionParameters['readTimeout'] ?? 0),
+                );
+            }
+        } catch (Throwable $exception) {
+            $message = sprintf('Error trying to connect to Redis DB. Error was: %s', $exception->getMessage());
+            $this->logger->error($message);
+            throw new StoreException($message, (int) $exception->getCode(), $exception);
+        }
+
+        try {
+            if (isset($connectionParameters['auth'])) {
+                $this->redis->auth($connectionParameters['auth']);
+            }
+        } catch (Throwable $exception) {
+            $message = sprintf('Error trying to set auth parameter for Redis. Error was: %s', $exception->getMessage());
+            $this->logger->error($message);
+            throw new StoreException($message);
+        }
+
+        try {
+            $this->redis->setOption(Redis::OPT_PREFIX, $connectionParameters['keyPrefix'] ?? 'ssp_accounting:');
+        } catch (Throwable $exception) {
+            $message = sprintf('Could not set key prefix for Redis. Error was: %s', $exception->getMessage());
+            $this->logger->error($message);
+            throw new StoreException($message, (int)$exception->getCode(), $exception);
+        }
+    }
+
+    /**
+     * @inheritDoc
+     * @throws StoreException
+     */
+    public function enqueue(JobInterface $job): void
+    {
+        try {
+            $listKey = $this->resolveListKeyForType(self::LIST_KEY_JOB, $job->getType());
+            $this->redis->rPush($listKey, serialize($job));
+        } catch (Throwable $exception) {
+            $message = sprintf('Could not add job to Redis list. Error was: %s', $exception->getMessage());
+            $this->logger->error($message);
+            throw new StoreException($message);
+        }
+    }
+
+    /**
+     * @inheritDoc
+     * @throws StoreException
+     */
+    public function dequeue(string $type): ?JobInterface
+    {
+        try {
+            $listKey = $this->resolveListKeyForType(self::LIST_KEY_JOB, $type);
+            if (!is_string($serializedJob = $this->redis->lPop($listKey))) {
+                return null;
+            }
+        } catch (Throwable $exception) {
+            $message = sprintf('Could not pop job from Redis list. Error was: %s', $exception->getMessage());
+            $this->logger->error($message);
+            throw new StoreException($message);
+        }
+
+        /** @var JobInterface|false $job */
+        $job = unserialize($serializedJob);
+
+        if ($job instanceof JobInterface) {
+            return $job;
+        }
+
+        $message = sprintf(
+            'Could not deserialize job entry which was available in Redis. Entry was %s.',
+            $serializedJob
+        );
+        $this->logger->error($message);
+        throw new StoreException($message);
+    }
+
+    /**
+     * @inheritDoc
+     * @throws StoreException
+     */
+    public function markFailedJob(JobInterface $job): void
+    {
+        try {
+            $listKey = $this->resolveListKeyForType(self::LIST_KEY_JOB_FAILED, $job->getType());
+            $this->redis->rPush($listKey, serialize($job));
+        } catch (Throwable $exception) {
+            $message = sprintf('Could not mark job as failed. Error was: %s', $exception->getMessage());
+            $this->logger->error($message);
+            throw new StoreException($message);
+        }
+    }
+
+    /**
+     * @throws StoreException
+     * @codeCoverageIgnore
+     */
+    public static function build(
+        ModuleConfiguration $moduleConfiguration,
+        LoggerInterface $logger,
+        string $connectionKey = null
+    ): self {
+        return new self(
+            $moduleConfiguration,
+            $logger,
+            $connectionKey
+        );
+    }
+
+    public function needsSetup(): bool
+    {
+        return false;
+    }
+
+    public function runSetup(): void
+    {
+        // No need for setup.
+    }
+
+    /**
+     * @return array
+     * @throws InvalidConfigurationException
+     */
+    protected function getConnectionParameters(): array
+    {
+        $connectionParameters = $this->moduleConfiguration->getConnectionParameters($this->connectionKey);
+
+        if (!isset($connectionParameters['host'])) {
+            $message = 'PhpRedis class Redis expects at least host option to be set, none given.';
+            $this->logger->error($message);
+            throw new InvalidConfigurationException($message);
+        }
+
+        return $connectionParameters;
+    }
+
+    /**
+     * @param string $list For example, job, job_failed...
+     * @param string $jobType For example, FQ class name of the job instance
+     * @return string Key with hashed type to conserve chars.
+     */
+    protected function resolveListKeyForType(string $list, string $jobType): string
+    {
+        return $list . ':' . sha1($jobType);
+    }
+}
diff --git a/src/Trackers/Authentication/DoctrineDbal/Versioned/Tracker.php b/src/Trackers/Authentication/DoctrineDbal/Versioned/Tracker.php
new file mode 100644
index 0000000..9c1971a
--- /dev/null
+++ b/src/Trackers/Authentication/DoctrineDbal/Versioned/Tracker.php
@@ -0,0 +1,106 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Trackers\Authentication\DoctrineDbal\Versioned;
+
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Module\accounting\Entities\Activity;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event;
+use SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider;
+use SimpleSAML\Module\accounting\Exceptions\InvalidConfigurationException;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Providers\Interfaces\AuthenticationDataProviderInterface;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+use SimpleSAML\Module\accounting\Stores\Builders\DataStoreBuilder;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store;
+use SimpleSAML\Module\accounting\Stores\Interfaces\DataStoreInterface;
+use SimpleSAML\Module\accounting\Trackers\Interfaces\AuthenticationDataTrackerInterface;
+
+class Tracker implements AuthenticationDataTrackerInterface, AuthenticationDataProviderInterface
+{
+    protected ModuleConfiguration $moduleConfiguration;
+    protected LoggerInterface $logger;
+    protected DataStoreInterface $dataStore;
+    protected HelpersManager $helpersManager;
+
+    public function __construct(
+        ModuleConfiguration $moduleConfiguration,
+        LoggerInterface $logger,
+        string $connectionType = ModuleConfiguration\ConnectionType::MASTER,
+        HelpersManager $helpersManager = null,
+        DataStoreInterface $dataStore = null
+    ) {
+        $this->moduleConfiguration = $moduleConfiguration;
+        $this->logger = $logger;
+
+        $this->helpersManager = $helpersManager ?? new HelpersManager();
+
+        // Use provided store or initialize default store for this tracker.
+        $this->dataStore = $dataStore ??
+            (new DataStoreBuilder($this->moduleConfiguration, $this->logger, $this->helpersManager))
+                ->build(
+                    Store::class,
+                    $this->moduleConfiguration->getClassConnectionKey(self::class),
+                    $connectionType
+                );
+    }
+
+    public static function build(
+        ModuleConfiguration $moduleConfiguration,
+        LoggerInterface $logger,
+        string $connectionType = ModuleConfiguration\ConnectionType::MASTER
+    ): self {
+        return new self($moduleConfiguration, $logger, $connectionType);
+    }
+
+    public function process(Event $authenticationEvent): void
+    {
+        $this->dataStore->persist($authenticationEvent);
+    }
+
+    public function needsSetup(): bool
+    {
+        return $this->dataStore->needsSetup();
+    }
+
+    public function runSetup(): void
+    {
+        if (! $this->needsSetup()) {
+            $this->logger->warning('Run setup called, however setup is not needed.');
+            return;
+        }
+
+        $this->dataStore->runSetup();
+    }
+
+    public function getConnectedServiceProviders(string $userIdentifier): ConnectedServiceProvider\Bag
+    {
+        $userIdentifierHashSha256 = $this->helpersManager->getHashHelper()->getSha256($userIdentifier);
+        return $this->dataStore->getConnectedOrganizations($userIdentifierHashSha256);
+    }
+
+    public function getActivity(string $userIdentifier, int $maxResults, int $firstResult): Activity\Bag
+    {
+        $userIdentifierHashSha256 = $this->helpersManager->getHashHelper()->getSha256($userIdentifier);
+        return $this->dataStore->getActivity($userIdentifierHashSha256, $maxResults, $firstResult);
+    }
+
+    public function enforceDataRetentionPolicy(\DateInterval $retentionPolicy): void
+    {
+        $dateTime = (new \DateTimeImmutable())->sub($retentionPolicy);
+
+        if ($dateTime === false) {
+            // @codeCoverageIgnoreStart
+            $message = sprintf(
+                'Could not create DateTime instance for data retention policy enforcement. Retention policy was: %s.',
+                var_export($retentionPolicy, true)
+            );
+            $this->logger->error($message);
+            throw new InvalidConfigurationException($message);
+            // @codeCoverageIgnoreEnd
+        }
+
+        $this->dataStore->deleteDataOlderThan($dateTime);
+    }
+}
diff --git a/src/Trackers/Builders/AuthenticationDataTrackerBuilder.php b/src/Trackers/Builders/AuthenticationDataTrackerBuilder.php
new file mode 100644
index 0000000..388338d
--- /dev/null
+++ b/src/Trackers/Builders/AuthenticationDataTrackerBuilder.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace SimpleSAML\Module\accounting\Trackers\Builders;
+
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Module\accounting\Exceptions\Exception;
+use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+use SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfigurationHelper;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+use SimpleSAML\Module\accounting\Trackers\Interfaces\AuthenticationDataTrackerInterface;
+use Throwable;
+
+class AuthenticationDataTrackerBuilder
+{
+    protected ModuleConfiguration $moduleConfiguration;
+    protected LoggerInterface $logger;
+    protected HelpersManager $helpersManager;
+
+    public function __construct(
+        ModuleConfiguration $moduleConfiguration,
+        LoggerInterface $logger,
+        HelpersManager $helpersManager
+    ) {
+        $this->moduleConfiguration = $moduleConfiguration;
+        $this->logger = $logger;
+        $this->helpersManager = $helpersManager;
+    }
+
+    /**
+     * @throws Exception
+     */
+    public function build(string $class): AuthenticationDataTrackerInterface
+    {
+        try {
+            // Make sure that the class implements proper interface
+            if (!is_subclass_of($class, AuthenticationDataTrackerInterface::class)) {
+                $message = sprintf(
+                    'Class %s does not implement interface %s.',
+                    $class,
+                    AuthenticationDataTrackerInterface::class
+                );
+                throw new UnexpectedValueException($message);
+            }
+
+            // Build...
+            /** @var AuthenticationDataTrackerInterface $store */
+            $store = $this->helpersManager->getInstanceBuilderUsingModuleConfigurationHelper()->build(
+                $class,
+                $this->moduleConfiguration,
+                $this->logger
+            );
+        } catch (Throwable $exception) {
+            $message = sprintf('Error building instance for class %s. Error was: %s', $class, $exception->getMessage());
+            throw new Exception($message, (int)$exception->getCode(), $exception);
+        }
+
+        return $store;
+    }
+}
diff --git a/src/Trackers/Interfaces/AuthenticationDataTrackerInterface.php b/src/Trackers/Interfaces/AuthenticationDataTrackerInterface.php
new file mode 100644
index 0000000..9a1f826
--- /dev/null
+++ b/src/Trackers/Interfaces/AuthenticationDataTrackerInterface.php
@@ -0,0 +1,21 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Module\accounting\Trackers\Interfaces;
+
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event;
+use SimpleSAML\Module\accounting\Interfaces\BuildableUsingModuleConfigurationInterface;
+use SimpleSAML\Module\accounting\Interfaces\SetupableInterface;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Providers\Interfaces\AuthenticationDataProviderInterface;
+
+interface AuthenticationDataTrackerInterface extends BuildableUsingModuleConfigurationInterface, SetupableInterface
+{
+    public static function build(ModuleConfiguration $moduleConfiguration, LoggerInterface $logger): self;
+
+    public function process(Event $authenticationEvent): void;
+
+    public function enforceDataRetentionPolicy(\DateInterval $retentionPolicy): void;
+}
diff --git a/templates/admin/configuration/status.twig b/templates/admin/configuration/status.twig
new file mode 100644
index 0000000..9927f73
--- /dev/null
+++ b/templates/admin/configuration/status.twig
@@ -0,0 +1,77 @@
+{# @var moduleConfiguration \SimpleSAML\Module\accounting\ModuleConfiguration #}
+
+{% set pagetitle = 'Configuration Status'|trans %}
+{% set frontpage_section = 'main' %}
+
+{% extends "base.twig" %}
+
+{% block content %}
+
+    <h2>{{ pagetitle }} </h2>
+
+    {% if configurationValidationErrors is not null %}
+        <p>{{ configurationValidationErrors }}</p>
+    {% elseif moduleConfiguration is not null %}
+        <ul>
+            <li>
+                <strong>{{ 'User ID Attribute Name'|trans }}</strong>: {{ moduleConfiguration.getUserIdAttributeName }}
+            </li>
+            <li>
+                <strong>{{ 'Accounting Processing Type'|trans }}</strong>:
+                {{ moduleConfiguration.getAccountingProcessingType }}
+            </li>
+            <li>
+                <strong>{{ 'Default Data Tracker and Provider Class'|trans }}</strong>:
+                {{ moduleConfiguration.getDefaultDataTrackerAndProviderClass }}
+            </li>
+            <li>
+                <strong>{{ 'Tracker and Provider Setup Needed'|trans }}</strong>:
+                {{ defaultDataTrackerAndProvider.needsSetup ? 'Yes'|trans : 'No'|trans }}
+            </li>
+            {% if additionalTrackers is not empty %}
+                <li>
+                    <strong>{{ 'Additional Trackers and setup'|trans }}</strong>:
+                    <ul>
+                        {% for trackerClass, trackerInstance in additionalTrackers %}
+                            <li>
+                                {{ trackerClass }}: {{ trackerInstance.needsSetup ? 'Yes'|trans : 'No'|trans }}
+                            </li>
+                        {% endfor %}
+                    </ul>
+                </li>
+            {% endif %}
+        </ul>
+
+        {% if moduleConfiguration.getAccountingProcessingType == 'asynchronous' %}
+            <ul>
+                <li>
+                    <strong>{{ 'Jobs Store Class'|trans }}</strong>: {{ moduleConfiguration.getJobsStoreClass }}
+                </li>
+                <li>
+                    {% if jobsStore is not null %}
+                        <strong>{{ 'Jobs Store Setup Needed'|trans }}</strong>:
+                        {{ jobsStore.needsSetup ? 'Yes'|trans : 'No'|trans }}
+                    {% else %}
+                        {{ 'Could not initialize jobs store.'|trans }}
+                    {% endif %}
+                </li>
+            </ul>
+        {% endif %}
+    {% else %}
+        <p>{{ 'Could not initialize module configuration.'|trans }}</p>
+    {% endif %}
+
+    <br>
+
+    {% if setupNeeded %}
+        <p>{{ 'Run setup before using the module.'|trans }}</p>
+        <a class="pure-button pure-button-warning" href="?runSetup=1">{{ 'Run Setup'|trans }}</a>
+    {% else %}
+        <p>
+            {{ 'Everything seems good to go.'|trans }}
+            <br>
+            <br>
+            {{ ' Profile page URL is'|trans }}: <a href="{{ profilePageUri }}">{{ profilePageUri }}</a>
+        </p>
+    {% endif %}
+{% endblock %}
diff --git a/templates/base.twig b/templates/base.twig
new file mode 100644
index 0000000..7465451
--- /dev/null
+++ b/templates/base.twig
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html lang="{{ currentLanguage }}">
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+{#    <meta name="viewport" content="initial-scale=1.0">#}
+{#    <meta http-equiv="X-UA-Compatible" content="IE=Edge">#}
+    <title>{{ pagetitle }}</title>
+    <link rel="stylesheet" href="{{ asset('css/src/default.css', 'accounting') }}">
+    <link rel="icon" href="{{ asset("icons/favicon.ico") }}">
+    <meta name="robots" content="noindex, nofollow">
+</head>
+<body id="{{ templateId }}">
+
+{% include '@accounting/includes/_header.twig' %}
+
+{% include '@accounting/includes/_navigation.twig' %}
+
+{% block banner %}{% endblock %}
+
+<section id="main">
+    {% block content %}{% endblock %}
+</section>
+
+<footer>
+    <div>
+        {% trans %}
+        As part of the GÉANT 2020 Framework Partnership Agreement (FPA), the project receives funding from the European
+        Union’s Horizon 2020 research and innovation programme under Grant Agreement No. 856726 (GN4-3).
+        {% endtrans %}
+    </div>
+</footer>
+</body>
+</html>
\ No newline at end of file
diff --git a/templates/includes/_header.twig b/templates/includes/_header.twig
new file mode 100644
index 0000000..5ba07d9
--- /dev/null
+++ b/templates/includes/_header.twig
@@ -0,0 +1,6 @@
+<header>
+    <div id="logo"><img src="{{ asset('css/src/icons/fppp-logo.svg', 'accounting') }}" alt="Profile Page Logo"/></div>
+    <label for="nav-toggle" class="nav-toggle-label">
+        <span></span>
+    </label>
+</header>
\ No newline at end of file
diff --git a/templates/includes/_navigation.twig b/templates/includes/_navigation.twig
new file mode 100644
index 0000000..a272262
--- /dev/null
+++ b/templates/includes/_navigation.twig
@@ -0,0 +1,40 @@
+<div id="nav">
+    <input type="checkbox" id="nav-toggle" class="nav-toggle">
+    <nav role="navigation" aria-label="XXX-pagedesc-XXX">
+        <ul>
+            <li>
+                <a href="personal-data">
+                    <span class="navicon">
+                        <img src="{{ asset('css/src/icons/prof-page.svg', 'accounting') }}" alt="Profile Page Icon"/>
+                    </span>
+                    <span>{{ 'Personal Data'|trans }}</span>
+                </a>
+            </li>
+            <li>
+                <a href="connected-organizations">
+                    <span class="navicon">
+                        <img src="{{ asset('css/src/icons/conn-orgs.svg', 'accounting') }}"
+                             alt="Connected Organizations Icon"/>
+                    </span>
+                    <span>{{ 'Connected Organizations'|trans }}</span>
+                </a>
+            </li>
+            <li>
+                <a href="activity">
+                    <span class="navicon">
+                        <img src="{{ asset('css/src/icons/activity.svg', 'accounting') }}" alt="Activity Icon"/>
+                    </span>
+                    <span>{{ 'Activity'|trans }}</span>
+                </a>
+            </li>
+            <li>
+                <a href="logout">
+                    <span class="navicon">
+                        <img src="{{ asset('css/src/icons/logout.svg', 'accounting') }}" alt="Logout Icon"/>
+                    </span>
+                    <span>{{ 'Log out'|trans }}</span>
+                </a>
+            </li>
+        </ul>
+    </nav>
+</div>
\ No newline at end of file
diff --git a/templates/user/activity.twig b/templates/user/activity.twig
new file mode 100644
index 0000000..514feeb
--- /dev/null
+++ b/templates/user/activity.twig
@@ -0,0 +1,68 @@
+{# @var activityBag \SimpleSAML\Module\accounting\Entities\Activity\Bag #}
+{# @var connectedServiceProvider \SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider #}
+
+{% extends "@accounting/base.twig" %}
+
+{% set pagetitle = 'Activity'|trans %}
+
+{% set pageMenuItem = 'activity' %}
+
+{% block content %}
+    <table>
+        <tr>
+            <th><strong>{{ 'Time'|trans }}</strong></th>
+            <th><strong>{{ 'Access'|trans }}</strong></th>
+            <th><strong>{{ 'Sent data'|trans }}</strong></th>
+        </tr>
+
+        {% for activity in activityBag.getAll %}
+            <tr class="accordion">
+                <td>{{ activity.getHappenedAt|date() }}</td>
+                <td>{{ activity.getServiceProvider.getName }}</td>
+                <td>
+                    {% for name in activity.getUser.getAttributes|keys %}
+                        {{ name|trans }}{% if not loop.last %}, {% endif %}
+                    {% endfor %}
+                </td>
+            </tr>
+            <tr>
+                <td class="dropdown-container" colspan="3">
+                    <input type="checkbox" id="dropdown-toggle-{{ loop.index }}" class="dropdown-toggle">
+                    <label class="dropdown-label" for="dropdown-toggle-{{ loop.index }}">
+                        <img src="{{ asset('css/src/icons/dropdown.svg', 'accounting') }}" alt="Dropdown icon">
+                    </label>
+                    <div class="dropdown-box">
+                        <strong>{{ 'IP address'|trans }}</strong>
+                        <ul><li>{{ activity.getClientIpAddress|default(' / ') }}</li></ul>
+
+                        <strong>{{ 'Information transfered to service'|trans }}</strong>
+                        <ul>
+                            {% for name, value in activity.getUser.getAttributes %}
+                                <li>
+                                    {{ name|trans }}: {{ value|join(', ') }}
+                                </li>
+                            {% endfor %}
+                        </ul>
+                    </div>
+                </td>
+            </tr>
+        {% else %}
+            <tr>
+                <td colspan="3">{{ 'No data available'|trans }}</td>
+            </tr>
+        {% endfor %}
+    </table>
+    <br>
+    <div class="center">
+        <div class="pagination">
+            {% if page > 1 %}
+                <a href="?page={{ page - 1 }}">❮</a>
+            {% endif %}
+
+            {% if activityBag.getAll|length == maxResults %}
+                <a href="?page={{ page + 1 }}">❯</a>
+            {% endif %}
+        </div>
+    </div>
+
+{% endblock %}
diff --git a/templates/user/activity.twig.bak b/templates/user/activity.twig.bak
new file mode 100644
index 0000000..5f77015
--- /dev/null
+++ b/templates/user/activity.twig.bak
@@ -0,0 +1,73 @@
+{# @var activityBag \SimpleSAML\Module\accounting\Entities\Activity\Bag #}
+{# @var connectedServiceProvider \SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider #}
+
+{% extends "@accounting/base.twig" %}
+
+{% set pagetitle = 'Activity'|trans %}
+
+{% set pageMenuItem = 'activity' %}
+
+{% block content %}
+
+    <h2>{{ pagetitle }} </h2>
+
+    <table class="pure-table pure-table-striped pure-table-attributes">
+        <thead>
+        <tr>
+            <th><strong>{{ 'Time'|trans }}</strong></th>
+            <th><strong>{{ 'Access'|trans }}</strong></th>
+            <th><strong>{{ 'Sent data'|trans }}</strong></th>
+        </tr>
+        </thead>
+        <tbody>
+        {% for activity in activityBag.getAll %}
+            <tr class="accordion">
+                <td>{{ activity.getHappenedAt|date() }}</td>
+                <td>{{ activity.getServiceProvider.getName }}</td>
+                <td>
+                    {% for name in activity.getUser.getAttributes|keys %}
+                        {{ name|trans }}{% if not loop.last %}, {% endif %}
+                    {% endfor %}
+                </td>
+            </tr>
+            <tr class="panel">
+                <td colspan="3">
+                    <strong>{{ 'IP address'|trans }}</strong>
+                    <ul><li>{{ activity.getClientIpAddress }}</li></ul>
+
+                    <strong>{{ 'Information transfered to service'|trans }}</strong>
+                    <ul>
+                        {% for name, value in activity.getUser.getAttributes %}
+                            <li>
+                                {{ name|trans }}: {{ value|join(', ') }}
+                            </li>
+                        {% endfor %}
+                    </ul>
+                </td>
+            </tr>
+        {% else %}
+            <tr>
+                <td colspan="3">{{ 'No data available'|trans }}</td>
+            </tr>
+        {% endfor %}
+        </tbody>
+    </table>
+    <br>
+    <div class="center">
+        <div class="pagination">
+            {% if page > 1 %}
+                <a href="?page={{ page - 1 }}">❮</a>
+            {% endif %}
+
+            {% if activityBag.getAll|length == maxResults %}
+                <a href="?page={{ page + 1 }}">❯</a>
+            {% endif %}
+        </div>
+    </div>
+
+{% endblock %}
+
+{% block postload %}
+    {{ parent() }}
+    {% include '@accounting/includes/_js-accordion.twig' %}
+{% endblock %}
\ No newline at end of file
diff --git a/templates/user/connected-organizations.twig b/templates/user/connected-organizations.twig
new file mode 100644
index 0000000..8bbe788
--- /dev/null
+++ b/templates/user/connected-organizations.twig
@@ -0,0 +1,66 @@
+{# @var connectedServiceProviderBag \SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider\Bag #}
+{# @var connectedServiceProvider \SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider #}
+
+{% extends "@accounting/base.twig" %}
+
+{% set pagetitle = 'Connected Organizations'|trans %}
+
+{% set pageMenuItem = 'connected-organizations' %}
+
+{% block content %}
+    <table>
+        <!-- fixed table header -->
+        <tr>
+            <th><strong>{{ 'Name'|trans }}</strong></th>
+            <th><strong>{{ 'All access'|trans }}</strong></th>
+            <th><strong>{{ 'Last access'|trans }}</strong></th>
+        </tr>
+
+        {% for connectedServiceProvider in connectedServiceProviderBag.getAll %}
+            <tr>
+                <td>{{ connectedServiceProvider.getServiceProvider.getName|e }}</td>
+                <td>{{ connectedServiceProvider.getNumberOfAuthentications|e }}</td>
+                <td>{{ connectedServiceProvider.getLastAuthenticationAt|date() }}</td>
+            </tr>
+            <tr>
+                <td class="dropdown-container" colspan="3">
+                    <input type="checkbox" id="dropdown-toggle-{{ loop.index }}" class="dropdown-toggle">
+                    <label class="dropdown-label" for="dropdown-toggle-{{ loop.index }}">
+                        <img src="{{ asset('css/src/icons/dropdown.svg', 'accounting') }}" alt="Dropdown icon">
+                    </label>
+                    <div class="dropdown-box">
+                        <strong>{{ 'Service details'|trans }}</strong>
+                        <ul>
+                            <li>{{ 'Entity ID'|trans }}: {{ connectedServiceProvider.getServiceProvider.getEntityId|e }}</li>
+                            <li>{{ 'Description'|trans }}: {{ connectedServiceProvider.getServiceProvider.getDescription|e|default(' / ') }}</li>
+                        </ul>
+
+                        <strong>{{ 'Information transfered to service'|trans }}</strong>
+                        <ul>
+                            {% for name, value in connectedServiceProvider.getUser.getAttributes %}
+                                <li>
+                                    {{ name|trans }}: {{ value|join(', ') }}
+                                </li>
+                            {% endfor %}
+                        </ul>
+
+                        <strong>{{ 'Login details'|trans }}</strong>
+                        <ul>
+                            <li>
+                                {{ 'First access'|trans }}: {{ connectedServiceProvider.getFirstAuthenticationAt|date() }}
+                            </li>
+                            <li>
+                                {{ 'Last access'|trans }}: {{ connectedServiceProvider.getLastAuthenticationAt|date() }}
+                            </li>
+                        </ul>
+                    </div>
+                </td>
+            </tr>
+        {% else %}
+            <tr>
+                <td colspan="3">{{ 'No data available'|trans }}</td>
+            </tr>
+        {% endfor %}
+        <!-- end of repeating item -->
+    </table>
+{% endblock %}
diff --git a/templates/user/connected-organizations.twig.bak b/templates/user/connected-organizations.twig.bak
new file mode 100644
index 0000000..0d5a578
--- /dev/null
+++ b/templates/user/connected-organizations.twig.bak
@@ -0,0 +1,70 @@
+{# @var connectedServiceProviderBag \SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider\Bag #}
+{# @var connectedServiceProvider \SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider #}
+
+{% extends "@accounting/base.twig" %}
+
+{% set pagetitle = 'Connected organizations'|trans %}
+
+{% set pageMenuItem = 'connected-organizations' %}
+
+{% block content %}
+
+    <h2>{{ pagetitle }} </h2>
+
+    <table class="pure-table pure-table-striped pure-table-attributes">
+        <thead>
+        <tr>
+            <th><strong>{{ 'Name'|trans }}</strong></th>
+            <th><strong>{{ 'All access'|trans }}</strong></th>
+            <th><strong>{{ 'Last access'|trans }}</strong></th>
+        </tr>
+        </thead>
+        <tbody>
+        {% for connectedServiceProvider in connectedServiceProviderBag.getAll %}
+            <tr class="accordion">
+                <td>{{ connectedServiceProvider.getServiceProvider.getName|e }}</td>
+                <td>{{ connectedServiceProvider.getNumberOfAuthentications|e }}</td>
+                <td>{{ connectedServiceProvider.getLastAuthenticationAt|date() }}</td>
+            </tr>
+            <tr class="panel">
+                <td colspan="3">
+                    <strong>{{ 'Service details'|trans }}</strong>
+                    <ul>
+                        <li>{{ 'Entity ID'|trans }}: {{ connectedServiceProvider.getServiceProvider.getEntityId|e }}</li>
+                        <li>{{ 'Description'|trans }}: {{ connectedServiceProvider.getServiceProvider.getDescription|e|default(' / ') }}</li>
+                    </ul>
+
+                    <strong>{{ 'Information transfered to service'|trans }}</strong>
+                    <ul>
+                        {% for name, value in connectedServiceProvider.getUser.getAttributes %}
+                            <li>
+                                {{ name|trans }}: {{ value|join(', ') }}
+                            </li>
+                        {% endfor %}
+                    </ul>
+
+                    <strong>{{ 'Login details'|trans }}</strong>
+                    <ul>
+                        <li>
+                            {{ 'First access'|trans }}: {{ connectedServiceProvider.getFirstAuthenticationAt|date() }}
+                        </li>
+                        <li>
+                            {{ 'Last access'|trans }}: {{ connectedServiceProvider.getLastAuthenticationAt|date() }}
+                        </li>
+                    </ul>
+                </td>
+            </tr>
+        {% else %}
+            <tr>
+                <td colspan="3">{{ 'No data available'|trans }}</td>
+            </tr>
+        {% endfor %}
+        </tbody>
+    </table>
+
+{% endblock %}
+
+{% block postload %}
+    {{ parent() }}
+    {% include '@accounting/includes/_js-accordion.twig' %}
+{% endblock %}
diff --git a/templates/user/personal-data.twig b/templates/user/personal-data.twig
new file mode 100644
index 0000000..ee0e606
--- /dev/null
+++ b/templates/user/personal-data.twig
@@ -0,0 +1,34 @@
+
+{% extends "@accounting/base.twig" %}
+
+{% set pagetitle = 'Personal Data'|trans %}
+
+{% set pageMenuItem = 'personal-data' %}
+
+{% block banner %}
+    <section id="banner">
+        <div>
+            {% trans %}This is what we know about you...{% endtrans %}
+        </div>
+    </section>
+{% endblock %}
+
+{% block content %}
+    <table>
+        <!-- fixed table header -->
+        <tr>
+            <th>{{ 'Attribute'|trans }}</th>
+            <th>{{ 'Your value'|trans }}</th>
+        </tr>
+
+        {% for name, value in normalizedAttributes %}
+            <tr>
+                <td>
+                    {{ name|trans }}
+                    <a href="#"><img src="{{ asset('css/src/icons/i.svg', 'accounting') }}" alt="Info icon"></a>
+                </td>
+                <td>{{ value }}</td>
+            </tr>
+        {% endfor %}
+    </table>
+{% endblock %}
diff --git a/templates/user/personal-data.twig.bak b/templates/user/personal-data.twig.bak
new file mode 100644
index 0000000..9aa3bc5
--- /dev/null
+++ b/templates/user/personal-data.twig.bak
@@ -0,0 +1,35 @@
+
+{% extends "@accounting/base.twig" %}
+
+{% set pagetitle = 'Personal Data'|trans %}
+
+{% set pageMenuItem = 'personal-data' %}
+
+{% block content %}
+
+    <h2>{{ pagetitle }} </h2>
+
+    <section id="banner">
+        <div>
+            {% trans %}This is what we know about you...{% endtrans %}
+        </div>
+    </section>
+
+    <table class="pure-table pure-table-striped pure-table-attributes">
+        <thead>
+            <tr>
+                <th><strong>Attribute</strong></th>
+                <th><strong>Your value</strong></th>
+            </tr>
+        </thead>
+        <tbody>
+            {% for name, value in normalizedAttributes %}
+                <tr>
+                    <td>{{ name|trans }}</td>
+                    <td>{{ value }}</td>
+                </tr>
+            {% endfor %}
+        </tbody>
+    </table>
+
+{% endblock %}
diff --git a/tests/attributemap/test.php b/tests/attributemap/test.php
new file mode 100644
index 0000000..3b756fa
--- /dev/null
+++ b/tests/attributemap/test.php
@@ -0,0 +1,8 @@
+<?php
+// phpcs:ignoreFile
+
+declare(strict_types=1);
+
+$attributemap = [
+    'mobile' => 'urn:mace:dir:attribute-def:mobile'
+];
diff --git a/tests/attributemap/test2.php b/tests/attributemap/test2.php
new file mode 100644
index 0000000..6d4443e
--- /dev/null
+++ b/tests/attributemap/test2.php
@@ -0,0 +1,8 @@
+<?php
+// phpcs:ignoreFile
+
+declare(strict_types=1);
+
+$attributemap = [
+    'phone' => 'urn:mace:dir:attribute-def:phone'
+];
diff --git a/tests/config-templates/config.php b/tests/config-templates/config.php
new file mode 100644
index 0000000..a6c0417
--- /dev/null
+++ b/tests/config-templates/config.php
@@ -0,0 +1,1161 @@
+<?php
+
+/**
+ * The configuration of SimpleSAMLphp
+ */
+
+$httpUtils = new \SimpleSAML\Utils\HTTP();
+
+$config = [
+
+    /*******************************
+     | BASIC CONFIGURATION OPTIONS |
+     *******************************/
+
+    /*
+     * Setup the following parameters to match your installation.
+     * See the user manual for more details.
+     */
+
+    /*
+     * baseurlpath is a *URL path* (not a filesystem path).
+     * A valid format for 'baseurlpath' is:
+     * [(http|https)://(hostname|fqdn)[:port]]/[path/to/simplesaml/]
+     *
+     * The full url format is useful if your SimpleSAMLphp setup is hosted behind
+     * a reverse proxy. In that case you can specify the external url here.
+     *
+     * Please note that SimpleSAMLphp will then redirect all queries to the
+     * external url, no matter where you come from (direct access or via the
+     * reverse proxy).
+     */
+    'baseurlpath' => 'simplesaml/',
+
+    /*
+     * The 'application' configuration array groups a set configuration options
+     * relative to an application protected by SimpleSAMLphp.
+     */
+    //'application' => [
+        /*
+         * The 'baseURL' configuration option allows you to specify a protocol,
+         * host and optionally a port that serves as the canonical base for all
+         * your application's URLs. This is useful when the environment
+         * observed in the server differs from the one observed by end users,
+         * for example, when using a load balancer to offload TLS.
+         *
+         * Note that this configuration option does not allow setting a path as
+         * part of the URL. If your setup involves URL rewriting or any other
+         * tricks that would result in SimpleSAMLphp observing a URL for your
+         * application's scripts different than the canonical one, you will
+         * need to compute the right URLs yourself and pass them dynamically
+         * to SimpleSAMLphp's API.
+         */
+        //'baseURL' => 'https://example.com',
+    //],
+
+    /*
+     * The following settings are *filesystem paths* which define where
+     * SimpleSAMLphp can find or write the following things:
+     * - 'certdir': The base directory for certificate and key material.
+     * - 'loggingdir': Where to write logs.
+     * - 'datadir': Storage of general data.
+     * - 'tempdir': Saving temporary files. SimpleSAMLphp will attempt to create
+     *   this directory if it doesn't exist.
+     * When specified as a relative path, this is relative to the SimpleSAMLphp
+     * root directory.
+     */
+    'certdir' => 'cert/',
+    'loggingdir' => 'log/',
+    'datadir' => 'data/',
+    'tempdir' => '/tmp/simplesaml',
+
+    /*
+     * Some information about the technical persons running this installation.
+     * The email address will be used as the recipient address for error reports, and
+     * also as the technical contact in generated metadata.
+     */
+    'technicalcontact_name' => 'Administrator',
+    'technicalcontact_email' => 'na@example.org',
+
+    /*
+     * (Optional) The method by which email is delivered.  Defaults to mail which utilizes the
+     * PHP mail() function.
+     *
+     * Valid options are: mail, sendmail and smtp.
+     */
+    //'mail.transport.method' => 'smtp',
+
+    /*
+     * Set the transport options for the transport method specified.  The valid settings are relative to the
+     * selected transport method.
+     */
+    // // smtp mail transport options
+    // 'mail.transport.options' => [
+    //     'host' => 'mail.example.org', // required
+    //     'port' => 25, // optional
+    //     'username' => 'user@example.org', // optional: if set, enables smtp authentication
+    //     'password' => 'password', // optional: if set, enables smtp authentication
+    //     'security' => 'tls', // optional: defaults to no smtp security
+    //     'smtpOptions' => [], // optional: passed to stream_context_create when connecting via SMTP
+    // ],
+    // // sendmail mail transport options
+    // 'mail.transport.options' => [
+    //     'path' => '/usr/sbin/sendmail' // optional: defaults to php.ini path
+    // ],
+
+    /*
+     * The envelope from address for outgoing emails.
+     * This should be in a domain that has your application's IP addresses in its SPF record
+     * to prevent it from being rejected by mail filters.
+     */
+    //'sendmail_from' => 'no-reply@example.org',
+
+    /*
+     * The timezone of the server. This option should be set to the timezone you want
+     * SimpleSAMLphp to report the time in. The default is to guess the timezone based
+     * on your system timezone.
+     *
+     * See this page for a list of valid timezones: http://php.net/manual/en/timezones.php
+     */
+    'timezone' => null,
+
+
+
+    /**********************************
+     | SECURITY CONFIGURATION OPTIONS |
+     **********************************/
+
+    /*
+     * This is a secret salt used by SimpleSAMLphp when it needs to generate a secure hash
+     * of a value. It must be changed from its default value to a secret value. The value of
+     * 'secretsalt' can be any valid string of any length.
+     *
+     * A possible way to generate a random salt is by running the following command from a unix shell:
+     * LC_ALL=C tr -c -d '0123456789abcdefghijklmnopqrstuvwxyz' </dev/urandom | dd bs=32 count=1 2>/dev/null;echo
+     */
+    'secretsalt' => 'defaultsecretsalt',
+
+    /*
+     * This password must be kept secret, and modified from the default value 123.
+     * This password will give access to the installation page of SimpleSAMLphp with
+     * metadata listing and diagnostics pages.
+     * You can also put a hash here; run "bin/pwgen.php" to generate one.
+     */
+    'auth.adminpassword' => '123',
+
+    /*
+     * Set this option to true if you want to require administrator password to access the metadata.
+     */
+    'admin.protectmetadata' => false,
+
+    /*
+     * Set this option to false if you don't want SimpleSAMLphp to check for new stable releases when
+     * visiting the configuration tab in the web interface.
+     */
+    'admin.checkforupdates' => true,
+
+    /*
+     * Array of domains that are allowed when generating links or redirects
+     * to URLs. SimpleSAMLphp will use this option to determine whether to
+     * to consider a given URL valid or not, but you should always validate
+     * URLs obtained from the input on your own (i.e. ReturnTo or RelayState
+     * parameters obtained from the $_REQUEST array).
+     *
+     * SimpleSAMLphp will automatically add your own domain (either by checking
+     * it dynamically, or by using the domain defined in the 'baseurlpath'
+     * directive, the latter having precedence) to the list of trusted domains,
+     * in case this option is NOT set to NULL. In that case, you are explicitly
+     * telling SimpleSAMLphp to verify URLs.
+     *
+     * Set to an empty array to disallow ALL redirects or links pointing to
+     * an external URL other than your own domain. This is the default behaviour.
+     *
+     * Set to NULL to disable checking of URLs. DO NOT DO THIS UNLESS YOU KNOW
+     * WHAT YOU ARE DOING!
+     *
+     * Example:
+     *   'trusted.url.domains' => ['sp.example.com', 'app.example.com'],
+     */
+    'trusted.url.domains' => [],
+
+    /*
+     * Enable regular expression matching of trusted.url.domains.
+     *
+     * Set to true to treat the values in trusted.url.domains as regular
+     * expressions. Set to false to do exact string matching.
+     *
+     * If enabled, the start and end delimiters ('^' and '$') will be added to
+     * all regular expressions in trusted.url.domains.
+     */
+    'trusted.url.regex' => false,
+
+    /*
+     * Enable secure POST from HTTPS to HTTP.
+     *
+     * If you have some SP's on HTTP and IdP is normally on HTTPS, this option
+     * enables secure POSTing to HTTP endpoint without warning from browser.
+     *
+     * For this to work, module.php/core/postredirect.php must be accessible
+     * also via HTTP on IdP, e.g. if your IdP is on
+     * https://idp.example.org/ssp/, then
+     * http://idp.example.org/ssp/module.php/core/postredirect.php must be accessible.
+     */
+    'enable.http_post' => false,
+
+    /*
+     * Set the allowed clock skew between encrypting/decrypting assertions
+     *
+     * If you have an server that is constantly out of sync, this option
+     * allows you to adjust the allowed clock-skew.
+     *
+     * Allowed range: 180 - 300
+     * Defaults to 180.
+     */
+    'assertion.allowed_clock_skew' => 180,
+
+
+    /************************
+     | ERRORS AND DEBUGGING |
+     ************************/
+
+    /*
+     * The 'debug' option allows you to control how SimpleSAMLphp behaves in certain
+     * situations where further action may be taken
+     *
+     * It can be left unset, in which case, debugging is switched off for all actions.
+     * If set, it MUST be an array containing the actions that you want to enable, or
+     * alternatively a hashed array where the keys are the actions and their
+     * corresponding values are booleans enabling or disabling each particular action.
+     *
+     * SimpleSAMLphp provides some pre-defined actions, though modules could add new
+     * actions here. Refer to the documentation of every module to learn if they
+     * allow you to set any more debugging actions.
+     *
+     * The pre-defined actions are:
+     *
+     * - 'saml': this action controls the logging of SAML messages exchanged with other
+     * entities. When enabled ('saml' is present in this option, or set to true), all
+     * SAML messages will be logged, including plaintext versions of encrypted
+     * messages.
+     *
+     * - 'backtraces': this action controls the logging of error backtraces so you
+     * can debug any possible errors happening in SimpleSAMLphp.
+     *
+     * - 'validatexml': this action allows you to validate SAML documents against all
+     * the relevant XML schemas. SAML 1.1 messages or SAML metadata parsed with
+     * the XML to SimpleSAMLphp metadata converter or the metaedit module will
+     * validate the SAML documents if this option is enabled.
+     *
+     * If you want to disable debugging completely, unset this option or set it to an
+     * empty array.
+     */
+    'debug' => [
+        'saml' => false,
+        'backtraces' => true,
+        'validatexml' => false,
+    ],
+
+    /*
+     * When 'showerrors' is enabled, all error messages and stack traces will be output
+     * to the browser.
+     *
+     * When 'errorreporting' is enabled, a form will be presented for the user to report
+     * the error to 'technicalcontact_email'.
+     */
+    'showerrors' => true,
+    'errorreporting' => true,
+
+    /*
+     * Custom error show function called from SimpleSAML\Error\Error::show.
+     * See docs/simplesamlphp-errorhandling.txt for function code example.
+     *
+     * Example:
+     *   'errors.show_function' => ['SimpleSAML\Module\example\Error', 'show'],
+     */
+
+
+
+    /**************************
+     | LOGGING AND STATISTICS |
+     **************************/
+
+    /*
+     * Define the minimum log level to log. Available levels:
+     * - SimpleSAML\Logger::ERR     No statistics, only errors
+     * - SimpleSAML\Logger::WARNING No statistics, only warnings/errors
+     * - SimpleSAML\Logger::NOTICE  Statistics and errors
+     * - SimpleSAML\Logger::INFO    Verbose logs
+     * - SimpleSAML\Logger::DEBUG   Full debug logs - not recommended for production
+     *
+     * Choose logging handler.
+     *
+     * Options: [syslog,file,errorlog,stderr]
+     *
+     */
+    'logging.level' => SimpleSAML\Logger::NOTICE,
+    'logging.handler' => 'syslog',
+
+    /*
+     * Specify the format of the logs. Its use varies depending on the log handler used (for instance, you cannot
+     * control here how dates are displayed when using the syslog or errorlog handlers), but in general the options
+     * are:
+     *
+     * - %date{<format>}: the date and time, with its format specified inside the brackets. See the PHP documentation
+     *   of the date() function for more information on the format. If the brackets are omitted, the standard
+     *   format is applied. This can be useful if you just want to control the placement of the date, but don't care
+     *   about the format.
+     *
+     * - %process: the name of the SimpleSAMLphp process. Remember you can configure this in the 'logging.processname'
+     *   option below.
+     *
+     * - %level: the log level (name or number depending on the handler used).
+     *
+     * - %stat: if the log entry is intended for statistical purposes, it will print the string 'STAT ' (bear in mind
+     *   the trailing space).
+     *
+     * - %trackid: the track ID, an identifier that allows you to track a single session.
+     *
+     * - %srcip: the IP address of the client. If you are behind a proxy, make sure to modify the
+     *   $_SERVER['REMOTE_ADDR'] variable on your code accordingly to the X-Forwarded-For header.
+     *
+     * - %msg: the message to be logged.
+     *
+     */
+    //'logging.format' => '%date{M j H:i:s} %process %level %stat[%trackid] %msg',
+
+    /*
+     * Choose which facility should be used when logging with syslog.
+     *
+     * These can be used for filtering the syslog output from SimpleSAMLphp into its
+     * own file by configuring the syslog daemon.
+     *
+     * See the documentation for openlog (http://php.net/manual/en/function.openlog.php) for available
+     * facilities. Note that only LOG_USER is valid on windows.
+     *
+     * The default is to use LOG_LOCAL5 if available, and fall back to LOG_USER if not.
+     */
+    'logging.facility' => defined('LOG_LOCAL5') ? constant('LOG_LOCAL5') : LOG_USER,
+
+    /*
+     * The process name that should be used when logging to syslog.
+     * The value is also written out by the other logging handlers.
+     */
+    'logging.processname' => 'simplesamlphp',
+
+    /*
+     * Logging: file - Logfilename in the loggingdir from above.
+     */
+    'logging.logfile' => 'simplesamlphp.log',
+
+    /*
+     * This is an array of outputs. Each output has at least a 'class' option, which
+     * selects the output.
+     */
+    'statistics.out' => [// Log statistics to the normal log.
+        /*
+        [
+            'class' => 'core:Log',
+            'level' => 'notice',
+        ],
+        */
+        // Log statistics to files in a directory. One file per day.
+        /*
+        [
+            'class' => 'core:File',
+            'directory' => '/var/log/stats',
+        ],
+        */
+    ],
+
+
+
+    /***********************
+     | PROXY CONFIGURATION |
+     ***********************/
+
+    /*
+     * Proxy to use for retrieving URLs.
+     *
+     * Example:
+     *   'proxy' => 'tcp://proxy.example.com:5100'
+     */
+    'proxy' => null,
+
+    /*
+     * Username/password authentication to proxy (Proxy-Authorization: Basic)
+     * Example:
+     *   'proxy.auth' = 'myuser:password'
+     */
+    //'proxy.auth' => 'myuser:password',
+
+
+
+    /**************************
+     | DATABASE CONFIGURATION |
+     **************************/
+
+    /*
+     * This database configuration is optional. If you are not using
+     * core functionality or modules that require a database, you can
+     * skip this configuration.
+     */
+
+    /*
+     * Database connection string.
+     * Ensure that you have the required PDO database driver installed
+     * for your connection string.
+     */
+    'database.dsn' => 'mysql:host=localhost;dbname=saml',
+
+    /*
+     * SQL database credentials
+     */
+    'database.username' => 'simplesamlphp',
+    'database.password' => 'secret',
+    'database.options' => [],
+
+    /*
+     * (Optional) Table prefix
+     */
+    'database.prefix' => '',
+
+    /*
+     * (Optional) Driver options
+     */
+    'database.driver_options' => [],
+
+    /*
+     * True or false if you would like a persistent database connection
+     */
+    'database.persistent' => false,
+
+    /*
+     * Database secondary configuration is optional as well. If you are only
+     * running a single database server, leave this blank. If you have
+     * a primary/secondary configuration, you can define as many secondary servers
+     * as you want here. Secondaries will be picked at random to be queried from.
+     *
+     * Configuration options in the secondary array are exactly the same as the
+     * options for the primary (shown above) with the exception of the table
+     * prefix and driver options.
+     */
+    'database.secondaries' => [
+        /*
+        [
+            'dsn' => 'mysql:host=mysecondary;dbname=saml',
+            'username' => 'simplesamlphp',
+            'password' => 'secret',
+            'persistent' => false,
+        ],
+        */
+    ],
+
+
+
+    /*************
+     | PROTOCOLS |
+     *************/
+
+    /*
+     * Which functionality in SimpleSAMLphp do you want to enable. Normally you would enable only
+     * one of the functionalities below, but in some cases you could run multiple functionalities.
+     * In example when you are setting up a federation bridge.
+     */
+    'enable.saml20-idp' => false,
+    'enable.adfs-idp' => false,
+
+
+
+    /***********
+     | MODULES |
+     ***********/
+
+    /*
+     * Configuration for enabling/disabling modules. By default the 'core', 'admin' and 'saml' modules are enabled.
+     *
+     * Example:
+     *
+     * 'module.enable' => [
+     *      'exampleauth' => true, // Setting to TRUE enables.
+     *      'consent' => false, // Setting to FALSE disables.
+     *      'core' => null, // Unset or NULL uses default.
+     * ],
+     */
+
+     'module.enable' => [
+         'exampleauth' => false,
+         'core' => true,
+         'admin' => true,
+         'saml' => true
+     ],
+
+
+    /*************************
+     | SESSION CONFIGURATION |
+     *************************/
+
+    /*
+     * This value is the duration of the session in seconds. Make sure that the time duration of
+     * cookies both at the SP and the IdP exceeds this duration.
+     */
+    'session.duration' => 8 * (60 * 60), // 8 hours.
+
+    /*
+     * Sets the duration, in seconds, data should be stored in the datastore. As the data store is used for
+     * login and logout requests, this option will control the maximum time these operations can take.
+     * The default is 4 hours (4*60*60) seconds, which should be more than enough for these operations.
+     */
+    'session.datastore.timeout' => (4 * 60 * 60), // 4 hours
+
+    /*
+     * Sets the duration, in seconds, auth state should be stored.
+     */
+    'session.state.timeout' => (60 * 60), // 1 hour
+
+    /*
+     * Option to override the default settings for the session cookie name
+     */
+    'session.cookie.name' => 'SimpleSAMLSessionID',
+
+    /*
+     * Expiration time for the session cookie, in seconds.
+     *
+     * Defaults to 0, which means that the cookie expires when the browser is closed.
+     *
+     * Example:
+     *  'session.cookie.lifetime' => 30*60,
+     */
+    'session.cookie.lifetime' => 0,
+
+    /*
+     * Limit the path of the cookies.
+     *
+     * Can be used to limit the path of the cookies to a specific subdirectory.
+     *
+     * Example:
+     *  'session.cookie.path' => '/simplesaml/',
+     */
+    'session.cookie.path' => '/',
+
+    /*
+     * Cookie domain.
+     *
+     * Can be used to make the session cookie available to several domains.
+     *
+     * Example:
+     *  'session.cookie.domain' => '.example.org',
+     */
+    'session.cookie.domain' => '',
+
+    /*
+     * Set the secure flag in the cookie.
+     *
+     * Set this to TRUE if the user only accesses your service
+     * through https. If the user can access the service through
+     * both http and https, this must be set to FALSE.
+     */
+    'session.cookie.secure' => true,
+
+    /*
+     * Set the SameSite attribute in the cookie.
+     *
+     * You can set this to the strings 'None', 'Lax', or 'Strict' to support
+     * the RFC6265bis SameSite cookie attribute. If set to null, no SameSite
+     * attribute will be sent.
+     *
+     * A value of "None" is required to properly support cross-domain POST
+     * requests which are used by different SAML bindings. Because some older
+     * browsers do not support this value, the canSetSameSiteNone function
+     * can be called to only set it for compatible browsers.
+     *
+     * You must also set the 'session.cookie.secure' value above to true.
+     *
+     * Example:
+     *  'session.cookie.samesite' => 'None',
+     */
+    'session.cookie.samesite' => $httpUtils->canSetSameSiteNone() ? 'None' : null,
+
+    /*
+     * Options to override the default settings for php sessions.
+     */
+    'session.phpsession.cookiename' => 'SimpleSAML',
+    'session.phpsession.savepath' => null,
+    'session.phpsession.httponly' => true,
+
+    /*
+     * Option to override the default settings for the auth token cookie
+     */
+    'session.authtoken.cookiename' => 'SimpleSAMLAuthToken',
+
+    /*
+     * Options for remember me feature for IdP sessions. Remember me feature
+     * has to be also implemented in authentication source used.
+     *
+     * Option 'session.cookie.lifetime' should be set to zero (0), i.e. cookie
+     * expires on browser session if remember me is not checked.
+     *
+     * Session duration ('session.duration' option) should be set according to
+     * 'session.rememberme.lifetime' option.
+     *
+     * It's advised to use remember me feature with session checking function
+     * defined with 'session.check_function' option.
+     */
+    'session.rememberme.enable' => false,
+    'session.rememberme.checked' => false,
+    'session.rememberme.lifetime' => (14 * 86400),
+
+    /*
+     * Custom function for session checking called on session init and loading.
+     * See docs/simplesamlphp-advancedfeatures.txt for function code example.
+     *
+     * Example:
+     *   'session.check_function' => ['\SimpleSAML\Module\example\Util', 'checkSession'],
+     */
+
+
+
+    /**************************
+     | MEMCACHE CONFIGURATION |
+     **************************/
+
+    /*
+     * Configuration for the 'memcache' session store. This allows you to store
+     * multiple redundant copies of sessions on different memcache servers.
+     *
+     * 'memcache_store.servers' is an array of server groups. Every data
+     * item will be mirrored in every server group.
+     *
+     * Each server group is an array of servers. The data items will be
+     * load-balanced between all servers in each server group.
+     *
+     * Each server is an array of parameters for the server. The following
+     * options are available:
+     *  - 'hostname': This is the hostname or ip address where the
+     *    memcache server runs. This is the only required option.
+     *  - 'port': This is the port number of the memcache server. If this
+     *    option isn't set, then we will use the 'memcache.default_port'
+     *    ini setting. This is 11211 by default.
+     *
+     * When using the "memcache" extension, the following options are also
+     * supported:
+     *  - 'weight': This sets the weight of this server in this server
+     *    group. http://php.net/manual/en/function.Memcache-addServer.php
+     *    contains more information about the weight option.
+     *  - 'timeout': The timeout for this server. By default, the timeout
+     *    is 3 seconds.
+     *
+     * Example of redundant configuration with load balancing:
+     * This configuration makes it possible to lose both servers in the
+     * a-group or both servers in the b-group without losing any sessions.
+     * Note that sessions will be lost if one server is lost from both the
+     * a-group and the b-group.
+     *
+     * 'memcache_store.servers' => [
+     *     [
+     *         ['hostname' => 'mc_a1'],
+     *         ['hostname' => 'mc_a2'],
+     *     ],
+     *     [
+     *         ['hostname' => 'mc_b1'],
+     *         ['hostname' => 'mc_b2'],
+     *     ],
+     * ],
+     *
+     * Example of simple configuration with only one memcache server,
+     * running on the same computer as the web server:
+     * Note that all sessions will be lost if the memcache server crashes.
+     *
+     * 'memcache_store.servers' => [
+     *     [
+     *         ['hostname' => 'localhost'],
+     *     ],
+     * ],
+     *
+     * Additionally, when using the "memcached" extension, unique keys must
+     * be provided for each group of servers if persistent connections are
+     * desired. Each server group can also have an "options" indexed array
+     * with the options desired for the given group:
+     *
+     * 'memcache_store.servers' => [
+     *     'memcache_group_1' => [
+     *         'options' => [
+     *              \Memcached::OPT_BINARY_PROTOCOL => true,
+     *              \Memcached::OPT_NO_BLOCK => true,
+     *              \Memcached::OPT_TCP_NODELAY => true,
+     *              \Memcached::OPT_LIBKETAMA_COMPATIBLE => true,
+     *         ],
+     *         ['hostname' => '127.0.0.1', 'port' => 11211],
+     *         ['hostname' => '127.0.0.2', 'port' => 11211],
+     *     ],
+     *
+     *     'memcache_group_2' => [
+     *         'options' => [
+     *              \Memcached::OPT_BINARY_PROTOCOL => true,
+     *              \Memcached::OPT_NO_BLOCK => true,
+     *              \Memcached::OPT_TCP_NODELAY => true,
+     *              \Memcached::OPT_LIBKETAMA_COMPATIBLE => true,
+     *         ],
+     *         ['hostname' => '127.0.0.3', 'port' => 11211],
+     *         ['hostname' => '127.0.0.4', 'port' => 11211],
+     *     ],
+     * ],
+     *
+     */
+    'memcache_store.servers' => [
+        [
+            ['hostname' => 'localhost'],
+        ],
+    ],
+
+    /*
+     * This value allows you to set a prefix for memcache-keys. The default
+     * for this value is 'simpleSAMLphp', which is fine in most cases.
+     *
+     * When running multiple instances of SSP on the same host, and more
+     * than one instance is using memcache, you probably want to assign
+     * a unique value per instance to this setting to avoid data collision.
+     */
+    'memcache_store.prefix' => '',
+
+    /*
+     * This value is the duration data should be stored in memcache. Data
+     * will be dropped from the memcache servers when this time expires.
+     * The time will be reset every time the data is written to the
+     * memcache servers.
+     *
+     * This value should always be larger than the 'session.duration'
+     * option. Not doing this may result in the session being deleted from
+     * the memcache servers while it is still in use.
+     *
+     * Set this value to 0 if you don't want data to expire.
+     *
+     * Note: The oldest data will always be deleted if the memcache server
+     * runs out of storage space.
+     */
+    'memcache_store.expires' => 36 * (60 * 60), // 36 hours.
+
+
+
+    /*************************************
+     | LANGUAGE AND INTERNATIONALIZATION |
+     *************************************/
+
+    /*
+     * Languages available, RTL languages, and what language is the default.
+     */
+    'language.available' => [
+        'en', 'no', 'nn', 'se', 'da', 'de', 'sv', 'fi', 'es', 'ca', 'fr', 'it', 'nl', 'lb',
+        'cs', 'sl', 'lt', 'hr', 'hu', 'pl', 'pt', 'pt-br', 'tr', 'ja', 'zh', 'zh-tw', 'ru',
+        'et', 'he', 'id', 'sr', 'lv', 'ro', 'eu', 'el', 'af', 'zu', 'xh', 'st',
+    ],
+    'language.rtl' => ['ar', 'dv', 'fa', 'ur', 'he'],
+    'language.default' => 'en',
+
+    /*
+     * Options to override the default settings for the language parameter
+     */
+    'language.parameter.name' => 'language',
+    'language.parameter.setcookie' => true,
+
+    /*
+     * Options to override the default settings for the language cookie
+     */
+    'language.cookie.name' => 'language',
+    'language.cookie.domain' => '',
+    'language.cookie.path' => '/',
+    'language.cookie.secure' => true,
+    'language.cookie.httponly' => false,
+    'language.cookie.lifetime' => (60 * 60 * 24 * 900),
+    'language.cookie.samesite' => $httpUtils->canSetSameSiteNone() ? 'None' : null,
+
+    /**
+     * Custom getLanguage function called from SimpleSAML\Locale\Language::getLanguage().
+     * Function should return language code of one of the available languages or NULL.
+     * See SimpleSAML\Locale\Language::getLanguage() source code for more info.
+     *
+     * This option can be used to implement a custom function for determining
+     * the default language for the user.
+     *
+     * Example:
+     *   'language.get_language_function' => ['\SimpleSAML\Module\example\Template', 'getLanguage'],
+     */
+
+    /**************
+     | APPEARANCE |
+     **************/
+
+    /*
+     * Which theme directory should be used?
+     */
+    'theme.use' => 'default',
+
+    /*
+     * Set this option to the text you would like to appear at the header of each page. Set to false if you don't want
+     * any text to appear in the header.
+     */
+    //'theme.header' => 'SimpleSAMLphp'
+
+    /**
+     * A template controller, if any.
+     *
+     * Used to intercept certain parts of the template handling, while keeping away unwanted/unexpected hooks. Set
+     * the 'theme.controller' configuration option to a class that implements the
+     * \SimpleSAML\XHTML\TemplateControllerInterface interface to use it.
+     */
+    //'theme.controller' => '',
+
+    /*
+     * Templating options
+     *
+     * By default, twig templates are not cached. To turn on template caching:
+     * Set 'template.cache' to an absolute path pointing to a directory that
+     * SimpleSAMLphp has read and write permissions to.
+     */
+    //'template.cache' => '',
+
+    /*
+     * Set the 'template.auto_reload' to true if you would like SimpleSAMLphp to
+     * recompile the templates (when using the template cache) if the templates
+     * change. If you don't want to check the source templates for every request,
+     * set it to false.
+     */
+    'template.auto_reload' => false,
+
+    /*
+     * Set this option to true to indicate that your installation of SimpleSAMLphp
+     * is running in a production environment. This will affect the way resources
+     * are used, offering an optimized version when running in production, and an
+     * easy-to-debug one when not. Set it to false when you are testing or
+     * developing the software, in which case a banner will be displayed to remind
+     * users that they're dealing with a non-production instance.
+     *
+     * Defaults to true.
+     */
+    'production' => true,
+
+    /*
+     * SimpleSAMLphp modules can host static resources which are served through PHP.
+     * The serving of the resources can be configured through these settings.
+     */
+    'assets' => [
+        /*
+         * These settings adjust the caching headers that are sent
+         * when serving static resources.
+         */
+        'caching' => [
+            /*
+             * Amount of seconds before the resource should be fetched again
+             */
+            'max_age' => 86400,
+            /*
+             * Calculate a checksum of every file and send it to the browser
+             * This allows the browser to avoid downloading assets again in situations
+             * where the Last-Modified header cannot be trusted,
+             * for example in cluster setups
+             *
+             * Defaults false
+             */
+            'etag' => false,
+        ],
+    ],
+
+    /**
+     * Set to a full URL if you want to redirect users that land on SimpleSAMLphp's
+     * front page to somewhere more useful. If left unset, a basic welcome message
+     * is shown.
+     */
+    //'frontpage.redirect' => 'https://example.com/',
+
+    /*********************
+     | DISCOVERY SERVICE |
+     *********************/
+
+    /*
+     * Whether the discovery service should allow the user to save his choice of IdP.
+     */
+    'idpdisco.enableremember' => true,
+    'idpdisco.rememberchecked' => true,
+
+    /*
+     * The disco service only accepts entities it knows.
+     */
+    'idpdisco.validate' => true,
+
+    'idpdisco.extDiscoveryStorage' => null,
+
+    /*
+     * IdP Discovery service look configuration.
+     * Wether to display a list of idp or to display a dropdown box. For many IdP' a dropdown box
+     * gives the best use experience.
+     *
+     * When using dropdown box a cookie is used to highlight the previously chosen IdP in the dropdown.
+     * This makes it easier for the user to choose the IdP
+     *
+     * Options: [links,dropdown]
+     */
+    'idpdisco.layout' => 'dropdown',
+
+
+
+    /*************************************
+     | AUTHENTICATION PROCESSING FILTERS |
+     *************************************/
+
+    /*
+     * Tracker processing filters that will be executed for all IdPs
+     */
+    'authproc.idp' => [
+        /* Enable the authproc filter below to add URN prefixes to all attributes
+        10 => array[
+            'class' => 'core:AttributeMap', 'addurnprefix'
+        ],
+        */
+        /* Enable the authproc filter below to automatically generated eduPersonTargetedID.
+        20 => 'core:TargetedID',
+        */
+
+        // Adopts language from attribute to use in UI
+        30 => 'core:LanguageAdaptor',
+
+        45 => [
+            'class'         => 'core:StatisticsWithAttribute',
+            'attributename' => 'realm',
+            'type'          => 'saml20-idp-SSO',
+        ],
+
+        /* When called without parameters, it will fallback to filter attributes 'the old way'
+         * by checking the 'attributes' parameter in metadata on IdP hosted and SP remote.
+         */
+        50 => 'core:AttributeLimit',
+
+        /*
+         * Search attribute "distinguishedName" for pattern and replaces if found
+         */
+        /*
+        60 => [
+            'class' => 'core:AttributeAlter',
+            'pattern' => '/OU=studerende/',
+            'replacement' => 'Student',
+            'subject' => 'distinguishedName',
+            '%replace',
+        ],
+        */
+
+        /*
+         * Consent module is enabled (with no permanent storage, using cookies).
+         */
+        /*
+        90 => [
+            'class' => 'consent:Consent',
+            'store' => 'consent:Cookie',
+            'focus' => 'yes',
+            'checked' => true
+        ],
+        */
+        // If language is set in Consent module it will be added as an attribute.
+        99 => 'core:LanguageAdaptor',
+    ],
+
+    /*
+     * Tracker processing filters that will be executed for all SPs
+     */
+    'authproc.sp' => [
+        /*
+        10 => [
+            'class' => 'core:AttributeMap', 'removeurnprefix'
+        ],
+        */
+
+        /*
+         * Generate the 'group' attribute populated from other variables, including eduPersonAffiliation.
+        60 => [
+            'class' => 'core:GenerateGroups', 'eduPersonAffiliation'
+        ],
+        */
+        /*
+         * All users will be members of 'users' and 'members'
+         */
+        /*
+        61 => [
+            'class' => 'core:AttributeAdd', 'groups' => ['users', 'members']
+        ],
+        */
+
+        // Adopts language from attribute to use in UI
+        90 => 'core:LanguageAdaptor',
+    ],
+
+
+
+    /**************************
+     | METADATA CONFIGURATION |
+     **************************/
+
+    /*
+     * This option allows you to specify a directory for your metadata outside of the standard metadata directory
+     * included in the standard distribution of the software.
+     */
+    'metadatadir' => 'metadata',
+
+    /*
+     * This option configures the metadata sources. The metadata sources is given as an array with
+     * different metadata sources. When searching for metadata, SimpleSAMLphp will search through
+     * the array from start to end.
+     *
+     * Each element in the array is an associative array which configures the metadata source.
+     * The type of the metadata source is given by the 'type' element. For each type we have
+     * different configuration options.
+     *
+     * Flat file metadata handler:
+     * - 'type': This is always 'flatfile'.
+     * - 'directory': The directory we will load the metadata files from. The default value for
+     *                this option is the value of the 'metadatadir' configuration option, or
+     *                'metadata/' if that option is unset.
+     *
+     * XML metadata handler:
+     * This metadata handler parses an XML file with either an EntityDescriptor element or an
+     * EntitiesDescriptor element. The XML file may be stored locally, or (for debugging) on a remote
+     * web server.
+     * The XML metadata handler defines the following options:
+     * - 'type': This is always 'xml'.
+     * - 'file': Path to the XML file with the metadata.
+     * - 'url': The URL to fetch metadata from. THIS IS ONLY FOR DEBUGGING - THERE IS NO CACHING OF THE RESPONSE.
+     *
+     * MDQ metadata handler:
+     * This metadata handler looks up for the metadata of an entity at the given MDQ server.
+     * The MDQ metadata handler defines the following options:
+     * - 'type': This is always 'mdq'.
+     * - 'server': Base URL of the MDQ server. Mandatory.
+     * - 'validateCertificate': The certificates file that may be used to sign the metadata. You don't need this
+     *                          option if you don't want to validate the signature on the metadata. Optional.
+     * - 'cachedir': Directory where metadata can be cached. Optional.
+     * - 'cachelength': Maximum time metadata can be cached, in seconds. Defaults to 24
+     *                  hours (86400 seconds). Optional.
+     *
+     * PDO metadata handler:
+     * This metadata handler looks up metadata of an entity stored in a database.
+     *
+     * Note: If you are using the PDO metadata handler, you must configure the database
+     * options in this configuration file.
+     *
+     * The PDO metadata handler defines the following options:
+     * - 'type': This is always 'pdo'.
+     *
+     * Examples:
+     *
+     * This example defines two flatfile sources. One is the default metadata directory, the other
+     * is a metadata directory with auto-generated metadata files.
+     *
+     * 'metadata.sources' => [
+     *     ['type' => 'flatfile'],
+     *     ['type' => 'flatfile', 'directory' => 'metadata-generated'],
+     * ],
+     *
+     * This example defines a flatfile source and an XML source.
+     * 'metadata.sources' => [
+     *     ['type' => 'flatfile'],
+     *     ['type' => 'xml', 'file' => 'idp.example.org-idpMeta.xml'],
+     * ],
+     *
+     * This example defines an mdq source.
+     * 'metadata.sources' => [
+     *      [
+     *          'type' => 'mdq',
+     *          'server' => 'http://mdq.server.com:8080',
+     *          'validateCertificate' => [
+     *              '/var/simplesamlphp/cert/metadata-key.new.crt',
+     *              '/var/simplesamlphp/cert/metadata-key.old.crt'
+     *          ],
+     *          'cachedir' => '/var/simplesamlphp/mdq-cache',
+     *          'cachelength' => 86400
+     *      ]
+     * ],
+     *
+     * This example defines an pdo source.
+     * 'metadata.sources' => [
+     *     ['type' => 'pdo']
+     * ],
+     *
+     * Default:
+     * 'metadata.sources' => [
+     *     ['type' => 'flatfile']
+     * ],
+     */
+    'metadata.sources' => [
+        ['type' => 'flatfile'],
+    ],
+
+    /*
+     * Should signing of generated metadata be enabled by default.
+     *
+     * Metadata signing can also be enabled for a individual SP or IdP by setting the
+     * same option in the metadata for the SP or IdP.
+     */
+    'metadata.sign.enable' => false,
+
+    /*
+     * The default key & certificate which should be used to sign generated metadata. These
+     * are files stored in the cert dir.
+     * These values can be overridden by the options with the same names in the SP or
+     * IdP metadata.
+     *
+     * If these aren't specified here or in the metadata for the SP or IdP, then
+     * the 'certificate' and 'privatekey' option in the metadata will be used.
+     * if those aren't set, signing of metadata will fail.
+     */
+    'metadata.sign.privatekey' => null,
+    'metadata.sign.privatekey_pass' => null,
+    'metadata.sign.certificate' => null,
+
+
+    /****************************
+     | DATA STORE CONFIGURATION |
+     ****************************/
+
+    /*
+     * Configure the data store for SimpleSAMLphp.
+     *
+     * - 'phpsession': Limited datastore, which uses the PHP session.
+     * - 'memcache': Key-value datastore, based on memcache.
+     * - 'sql': SQL datastore, using PDO.
+     * - 'redis': Key-value datastore, based on redis.
+     *
+     * The default datastore is 'phpsession'.
+     */
+    'store.type'                    => 'phpsession',
+
+    /*
+     * The DSN the sql datastore should connect to.
+     *
+     * See http://www.php.net/manual/en/pdo.drivers.php for the various
+     * syntaxes.
+     */
+    'store.sql.dsn'                 => 'sqlite:/path/to/sqlitedatabase.sq3',
+
+    /*
+     * The username and password to use when connecting to the database.
+     */
+    'store.sql.username' => null,
+    'store.sql.password' => null,
+
+    /*
+     * The prefix we should use on our tables.
+     */
+    'store.sql.prefix' => 'SimpleSAMLphp',
+
+    /*
+     * The driver-options we should pass to the PDO-constructor.
+     */
+    'store.sql.options' => [],
+
+    /*
+     * The hostname and port of the Redis datastore instance.
+     */
+    'store.redis.host' => 'localhost',
+    'store.redis.port' => 6379,
+
+    /*
+     * The prefix we should use on our Redis datastore.
+     */
+    'store.redis.prefix' => 'SimpleSAMLphp',
+];
diff --git a/tests/config-templates/module_accounting.php b/tests/config-templates/module_accounting.php
new file mode 100644
index 0000000..882170b
--- /dev/null
+++ b/tests/config-templates/module_accounting.php
@@ -0,0 +1,61 @@
+<?php
+
+declare(strict_types=1);
+
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Providers;
+use SimpleSAML\Module\accounting\Stores;
+use SimpleSAML\Module\accounting\Trackers;
+
+$config = [
+
+    ModuleConfiguration::OPTION_USER_ID_ATTRIBUTE_NAME => 'urn:oasis:names:tc:SAML:attribute:subject-id',
+
+    ModuleConfiguration::OPTION_DEFAULT_AUTHENTICATION_SOURCE => 'default-sp',
+
+    ModuleConfiguration::OPTION_ACCOUNTING_PROCESSING_TYPE =>
+        ModuleConfiguration\AccountingProcessingType::VALUE_SYNCHRONOUS,
+
+    ModuleConfiguration::OPTION_JOBS_STORE => Stores\Jobs\DoctrineDbal\Store::class,
+
+    ModuleConfiguration::OPTION_DEFAULT_DATA_TRACKER_AND_PROVIDER =>
+        Trackers\Authentication\DoctrineDbal\Versioned\Tracker::class,
+
+    ModuleConfiguration::OPTION_ADDITIONAL_TRACKERS => [
+        //
+    ],
+
+    ModuleConfiguration::OPTION_CLASS_TO_CONNECTION_MAP => [
+        Stores\Jobs\DoctrineDbal\Store::class => 'doctrine_dbal_pdo_sqlite',
+        Trackers\Authentication\DoctrineDbal\Versioned\Tracker::class => [
+            ModuleConfiguration\ConnectionType::MASTER => 'doctrine_dbal_pdo_sqlite',
+            ModuleConfiguration\ConnectionType::SLAVE => [
+                'doctrine_dbal_pdo_sqlite_slave',
+            ],
+        ],
+    ],
+
+    ModuleConfiguration::OPTION_CONNECTIONS_AND_PARAMETERS => [
+        'doctrine_dbal_pdo_sqlite' => [
+            'driver' => 'pdo_sqlite',
+            'memory' => true,
+            'table_prefix' => '',
+        ],
+        'doctrine_dbal_pdo_sqlite_slave' => [
+            'driver' => 'pdo_sqlite',
+            'memory' => true,
+            'table_prefix' => '',
+        ],
+    ],
+
+    ModuleConfiguration::OPTION_JOB_RUNNER_MAXIMUM_EXECUTION_TIME => null,
+
+    ModuleConfiguration::OPTION_JOB_RUNNER_SHOULD_PAUSE_AFTER_NUMBER_OF_JOBS_PROCESSED => 10,
+
+    ModuleConfiguration::OPTION_TRACKER_DATA_RETENTION_POLICY => null,
+
+    ModuleConfiguration::OPTION_CRON_TAG_FOR_TRACKER_DATA_RETENTION_POLICY =>
+        'accounting_tracker_data_retention_policy',
+
+    ModuleConfiguration::OPTION_CRON_TAG_FOR_JOB_RUNNER => 'accounting_job_runner',
+];
diff --git a/tests/src/Auth/Process/AccountingTest.php b/tests/src/Auth/Process/AccountingTest.php
new file mode 100644
index 0000000..7e932e0
--- /dev/null
+++ b/tests/src/Auth/Process/AccountingTest.php
@@ -0,0 +1,182 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Auth\Process;
+
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Module\accounting\Auth\Process\Accounting;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event;
+use SimpleSAML\Module\accounting\Entities\Authentication\State;
+use SimpleSAML\Module\accounting\Exceptions\InvalidConfigurationException;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+use SimpleSAML\Module\accounting\Stores\Builders\JobsStoreBuilder;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Factory;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator;
+use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store;
+use SimpleSAML\Module\accounting\Trackers\Authentication\DoctrineDbal\Versioned\Tracker;
+use SimpleSAML\Module\accounting\Trackers\Builders\AuthenticationDataTrackerBuilder;
+use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Auth\Process\Accounting
+ * @uses   \SimpleSAML\Module\accounting\Entities\Authentication\Event
+ * @uses   \SimpleSAML\Module\accounting\Entities\Authentication\State
+ * @uses   \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection
+ * @uses   \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator
+ * @uses   \SimpleSAML\Module\accounting\Stores\Builders\Bases\AbstractStoreBuilder
+ * @uses   \SimpleSAML\Module\accounting\Trackers\Builders\AuthenticationDataTrackerBuilder
+ * @uses   \SimpleSAML\Module\accounting\Entities\Authentication\Event\Job
+ * @uses   \SimpleSAML\Module\accounting\Entities\Bases\AbstractJob
+ * @uses   \SimpleSAML\Module\accounting\Helpers\NetworkHelper
+ * @uses   \SimpleSAML\Module\accounting\Services\HelpersManager
+ */
+class AccountingTest extends TestCase
+{
+    protected \PHPUnit\Framework\MockObject\Stub $moduleConfigurationStub;
+    protected \PHPUnit\Framework\MockObject\MockObject $loggerMock;
+    protected array $filterConfig;
+    protected \PHPUnit\Framework\MockObject\MockObject $jobsStoreBuilderMock;
+    protected \PHPUnit\Framework\MockObject\MockObject $authenticationDataTrackerBuilderMock;
+    protected \PHPUnit\Framework\MockObject\MockObject $jobsStoreMock;
+    protected \PHPUnit\Framework\MockObject\MockObject $trackerMock;
+    protected array $sampleState;
+    protected HelpersManager $helpersManager;
+
+    protected function setUp(): void
+    {
+        $this->moduleConfigurationStub = $this->createStub(ModuleConfiguration::class);
+
+        $this->loggerMock = $this->createMock(LoggerInterface::class);
+
+        $this->jobsStoreBuilderMock = $this->createMock(JobsStoreBuilder::class);
+        $this->authenticationDataTrackerBuilderMock =
+            $this->createMock(AuthenticationDataTrackerBuilder::class);
+
+        $this->jobsStoreMock = $this->createMock(Store::class);
+        $this->trackerMock = $this->createMock(Tracker::class);
+
+        $this->sampleState = StateArrays::FULL;
+
+        $this->filterConfig = [];
+
+        $this->helpersManager = new HelpersManager();
+    }
+
+    public function testCanCreateInstance(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $this->assertInstanceOf(
+            Accounting::class,
+            new Accounting(
+                $this->filterConfig,
+                null,
+                $this->moduleConfigurationStub,
+                $this->loggerMock,
+            )
+        );
+
+        /** @psalm-suppress InvalidArgument */
+        $this->assertInstanceOf(
+            Accounting::class,
+            new Accounting(
+                $this->filterConfig,
+                null,
+                $this->moduleConfigurationStub,
+                $this->loggerMock,
+                $this->helpersManager,
+                $this->jobsStoreBuilderMock,
+                $this->authenticationDataTrackerBuilderMock
+            )
+        );
+    }
+
+    public function testCreatesJobOnAsynchronousAccountingType(): void
+    {
+        $this->moduleConfigurationStub->method('getAccountingProcessingType')
+            ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
+        $this->moduleConfigurationStub->method('getJobsStoreClass')
+            ->willReturn(Store::class);
+
+        $this->jobsStoreMock->expects($this->once())
+            ->method('enqueue')
+            ->with($this->isInstanceOf(Event\Job::class));
+
+        $this->jobsStoreBuilderMock->expects($this->once())
+            ->method('build')
+            ->with($this->equalTo(Store::class))
+            ->willReturn($this->jobsStoreMock);
+
+        $this->authenticationDataTrackerBuilderMock
+            ->expects($this->never())
+            ->method('build');
+
+        /** @psalm-suppress InvalidArgument */
+        (new Accounting(
+            $this->filterConfig,
+            null,
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManager,
+            $this->jobsStoreBuilderMock,
+            $this->authenticationDataTrackerBuilderMock
+        ))->process($this->sampleState);
+    }
+
+    public function testAccountingRunsOnSynchronousType(): void
+    {
+        $this->moduleConfigurationStub->method('getAccountingProcessingType')
+            ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_SYNCHRONOUS);
+
+        $this->moduleConfigurationStub->method('getDefaultDataTrackerAndProviderClass')
+            ->willReturn(Tracker::class);
+        $this->moduleConfigurationStub->method('getAdditionalTrackers')->willReturn([]);
+
+        $this->jobsStoreBuilderMock->expects($this->never())
+            ->method('build');
+
+        $this->trackerMock
+            ->expects($this->once())
+            ->method('process')
+            ->with($this->isInstanceOf(Event::class));
+
+        $this->authenticationDataTrackerBuilderMock
+            ->expects($this->once())
+            ->method('build')
+            ->with($this->equalTo(Tracker::class))
+            ->willReturn($this->trackerMock);
+
+        /** @psalm-suppress InvalidArgument */
+        (new Accounting(
+            $this->filterConfig,
+            null,
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManager,
+            $this->jobsStoreBuilderMock,
+            $this->authenticationDataTrackerBuilderMock
+        ))->process($this->sampleState);
+    }
+
+    public function testLogsErrorOnException(): void
+    {
+        $this->moduleConfigurationStub->method('getAccountingProcessingType')
+            ->willThrowException(new InvalidConfigurationException('test'));
+
+        $this->loggerMock->expects($this->once())->method('error');
+
+        /** @psalm-suppress InvalidArgument */
+        (new Accounting(
+            $this->filterConfig,
+            null,
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManager,
+            $this->jobsStoreBuilderMock,
+            $this->authenticationDataTrackerBuilderMock
+        ))->process($this->sampleState);
+    }
+}
diff --git a/tests/src/Constants/ConnectionParameters.php b/tests/src/Constants/ConnectionParameters.php
new file mode 100644
index 0000000..9aad77a
--- /dev/null
+++ b/tests/src/Constants/ConnectionParameters.php
@@ -0,0 +1,10 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Constants;
+
+class ConnectionParameters
+{
+    public const DBAL_SQLITE_MEMORY = ['driver' => 'pdo_sqlite', 'memory' => true,];
+}
diff --git a/tests/src/Constants/DateTime.php b/tests/src/Constants/DateTime.php
new file mode 100644
index 0000000..df07b19
--- /dev/null
+++ b/tests/src/Constants/DateTime.php
@@ -0,0 +1,10 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Constants;
+
+final class DateTime
+{
+    public const DEFAULT_FORMAT = 'Y-m-d H:i:s';
+}
diff --git a/tests/src/Constants/RawRowResult.php b/tests/src/Constants/RawRowResult.php
new file mode 100644
index 0000000..e4224df
--- /dev/null
+++ b/tests/src/Constants/RawRowResult.php
@@ -0,0 +1,27 @@
+<?php
+// phpcs:ignoreFile
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Constants;
+
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\TableConstants;
+
+class RawRowResult
+{
+    public const CONNECTED_ORGANIZATION = [
+        TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_NUMBER_OF_AUTHENTICATIONS => 1,
+        TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_LAST_AUTHENTICATION_AT => '2022-02-22 22:22:22',
+        TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_FIRST_AUTHENTICATION_AT => '2022-02-02 22:22:22',
+        TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_SP_METADATA => 'a:9:{s:19:"SingleLogoutService";a:1:{i:0;a:2:{s:7:"Binding";s:50:"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect";s:8:"Location";s:121:"https://pc-mivancic.srce.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/singleLogoutService/default-sp";}}s:24:"AssertionConsumerService";a:2:{i:0;a:3:{s:7:"Binding";s:46:"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST";s:8:"Location";s:126:"https://pc-mivancic.srce.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/assertionConsumerService/default-sp";s:5:"index";i:0;}i:1;a:3:{s:7:"Binding";s:50:"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact";s:8:"Location";s:126:"https://pc-mivancic.srce.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/assertionConsumerService/default-sp";s:5:"index";i:1;}}s:8:"contacts";a:1:{i:0;a:3:{s:12:"emailAddress";s:15:"mivanci@srce.hr";s:9:"givenName";s:15:"Marko Ivančić";s:11:"contactType";s:9:"technical";}}s:4:"name";a:1:{s:2:"en";s:12:"Test service";}s:11:"description";a:1:{s:2:"en";s:27:"Description of test service";}s:16:"OrganizationName";a:1:{s:2:"en";s:17:"Test organization";}s:8:"entityid";s:114:"https://pc-mivancic.srce.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/metadata.php/default-sp";s:14:"metadata-index";s:114:"https://pc-mivancic.srce.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/metadata.php/default-sp";s:12:"metadata-set";s:16:"saml20-sp-remote";}',
+        TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_USER_ATTRIBUTES => 'a:5:{s:33:"urn:oid:0.9.2342.19200300.100.1.1";a:1:{i:0;s:11:"student-uid";}s:32:"urn:oid:1.3.6.1.4.1.5923.1.1.1.1";a:2:{i:0;s:6:"member";i:1;s:7:"student";}s:15:"urn:oid:2.5.4.4";a:1:{i:0;s:10:"student-sn";}s:19:"hrEduPersonUniqueID";a:1:{i:0;s:19:"student@example.org";}s:23:"hrEduPersonPersistentID";a:1:{i:0;s:13:"student123abc";}}',
+    ];
+
+
+    public const ACTIVITY = [
+        TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_HAPPENED_AT => '2022-02-22 22:22:22',
+        TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_SP_METADATA => 'a:9:{s:19:"SingleLogoutService";a:1:{i:0;a:2:{s:7:"Binding";s:50:"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect";s:8:"Location";s:121:"https://pc-mivancic.srce.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/singleLogoutService/default-sp";}}s:24:"AssertionConsumerService";a:2:{i:0;a:3:{s:7:"Binding";s:46:"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST";s:8:"Location";s:126:"https://pc-mivancic.srce.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/assertionConsumerService/default-sp";s:5:"index";i:0;}i:1;a:3:{s:7:"Binding";s:50:"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact";s:8:"Location";s:126:"https://pc-mivancic.srce.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/assertionConsumerService/default-sp";s:5:"index";i:1;}}s:8:"contacts";a:1:{i:0;a:3:{s:12:"emailAddress";s:15:"mivanci@srce.hr";s:9:"givenName";s:15:"Marko Ivančić";s:11:"contactType";s:9:"technical";}}s:4:"name";a:1:{s:2:"en";s:12:"Test service";}s:11:"description";a:1:{s:2:"en";s:27:"Description of test service";}s:16:"OrganizationName";a:1:{s:2:"en";s:17:"Test organization";}s:8:"entityid";s:114:"https://pc-mivancic.srce.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/metadata.php/default-sp";s:14:"metadata-index";s:114:"https://pc-mivancic.srce.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/metadata.php/default-sp";s:12:"metadata-set";s:16:"saml20-sp-remote";}',
+        TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_USER_ATTRIBUTES => 'a:5:{s:33:"urn:oid:0.9.2342.19200300.100.1.1";a:1:{i:0;s:11:"student-uid";}s:32:"urn:oid:1.3.6.1.4.1.5923.1.1.1.1";a:2:{i:0;s:6:"member";i:1;s:7:"student";}s:15:"urn:oid:2.5.4.4";a:1:{i:0;s:10:"student-sn";}s:19:"hrEduPersonUniqueID";a:1:{i:0;s:19:"student@example.org";}s:23:"hrEduPersonPersistentID";a:1:{i:0;s:13:"student123abc";}}',
+        TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_CLIENT_IP_ADDRESS => '172.21.0.1',
+    ];
+}
diff --git a/tests/src/Constants/SerializedJob.php b/tests/src/Constants/SerializedJob.php
new file mode 100644
index 0000000..703c055
--- /dev/null
+++ b/tests/src/Constants/SerializedJob.php
@@ -0,0 +1,12 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Constants;
+
+use SimpleSAML\Module\accounting\Entities\Authentication\Event\Job;
+
+class SerializedJob
+{
+    public const EVENT = [
+        Job::class => 'TODO'
+    ];
+}
diff --git a/tests/src/Constants/StateArrays.php b/tests/src/Constants/StateArrays.php
new file mode 100644
index 0000000..e18b082
--- /dev/null
+++ b/tests/src/Constants/StateArrays.php
@@ -0,0 +1,134 @@
+<?php
+// phpcs:ignoreFile
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Constants;
+
+final class StateArrays
+{
+    public const FULL = [
+        'Responder' => [0 => '\\SimpleSAML\\Module\\saml\\IdP\\SAML2', 1 => 'sendResponse',],
+        '\\SimpleSAML\\Auth\\State.exceptionFunc' => [
+            0 => '\\SimpleSAML\\Module\\saml\\IdP\\SAML2',
+            1 => 'handleAuthError',
+        ],
+        '\\SimpleSAML\\Auth\\State.restartURL' => 'https://localhost.someone.from.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/saml2/idp/SSOService.php?spentityid=https%3A%2F%2Fpc-example.org.hr%3A9074%2Fsimplesamlphp%2Fsimplesamlphp-2-beta-git%2Fmodule.php%2Fsaml%2Fsp%2Fmetadata.php%2Fdefault-sp&RelayState=https%3A%2F%2Flocalhost.someone.from.hr%3A9074%2Fsimplesamlphp%2Fsimplesamlphp-2-beta-git%2Fmodule.php%2Fadmin%2Ftest%2Fdefault-sp&cookieTime=1660912195',
+        'SPMetadata' => [
+            'SingleLogoutService' => [
+                0 => [
+                    'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
+                    'Location' => 'https://pc-example.org.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/singleLogoutService/default-sp',
+                ],
+            ],
+            'AssertionConsumerService' => [
+                0 => [
+                    'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',
+                    'Location' => 'https://pc-example.org.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/assertionConsumerService/default-sp',
+                    'index' => 0,
+                ],
+                1 => [
+                    'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact',
+                    'Location' => 'https://pc-example.org.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/assertionConsumerService/default-sp',
+                    'index' => 1,
+                ],
+            ],
+            'contacts' => [
+                0 => [
+                    'emailAddress' => 'example@org.hr',
+                    'givenName' => 'Marko Ivančić',
+                    'contactType' => 'technical',
+                ],
+            ],
+            'entityid' => 'https://pc-example.org.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/metadata.php/default-sp',
+            'metadata-index' => 'https://pc-example.org.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/metadata.php/default-sp',
+            'metadata-set' => 'saml20-sp-remote',
+            'name' => 'Test service',
+            'description' => 'Test service description'
+        ],
+        'saml:RelayState' => 'https://localhost.someone.from.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/admin/test/default-sp',
+        'saml:RequestId' => null,
+        'saml:IDPList' => [],
+        'saml:ProxyCount' => null,
+        'saml:RequesterID' => null,
+        'ForceAuthn' => false,
+        'isPassive' => false,
+        'saml:ConsumerURL' => 'https://pc-example.org.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/assertionConsumerService/default-sp',
+        'saml:Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',
+        'saml:NameIDFormat' => null,
+        'saml:AllowCreate' => true,
+        'saml:Extensions' => null,
+        'saml:AuthnRequestReceivedAt' => 1660912195.505402,
+        'saml:RequestedAuthnContext' => null,
+        'core:IdP' => 'saml2:https://localhost.someone.from.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/saml2/idp/metadata.php',
+        'core:SP' => 'https://pc-example.org.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/metadata.php/default-sp',
+        'IdPMetadata' => [
+            'host' => 'localhost.someone.from.hr',
+            'privatekey' => 'key.pem',
+            'certificate' => 'cert.pem',
+            'auth' => 'example-userpass',
+            'attributes.NameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri',
+            'authproc' => [100 => ['class' => 'core:AttributeMap', 0 => 'name2oid',],],
+            'entityid' => 'https://localhost.someone.from.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/saml2/idp/metadata.php',
+            'metadata-index' => 'https://localhost.someone.from.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/saml2/idp/metadata.php',
+            'metadata-set' => 'saml20-idp-hosted',
+        ],
+        'ReturnCallback' => [0 => '\\SimpleSAML\\IdP', 1 => 'postAuth',],
+        'Attributes' => [
+            'hrEduPersonUniqueID' => [0 => 'testuser@primjer.hr',],
+            'urn:oid:0.9.2342.19200300.100.1.1' => [0 => 'testuser',],
+            'urn:oid:2.5.4.4' => [0 => 'TestSurname', 1 => 'TestSurname2',],
+            'urn:oid:2.5.4.42' => [0 => 'TestName',],
+            'urn:oid:2.5.4.10' => [0 => 'Testna ustanova',],
+            'urn:oid:2.5.4.11' => [0 => 'Testna org jedinica',],
+            'hrEduPersonPersistentID' => [0 => 'da4294fb4e5746d57ab6ad88d2daf275',],
+            'updatedAt' => [0 => '123456789',],
+        ],
+        'Authority' => 'example-userpass',
+        'AuthnInstant' => 1660911943,
+        'Expire' => 1660940743,
+        'ReturnCall' => [0 => '\\SimpleSAML\\IdP', 1 => 'postAuthProc',],
+        'Destination' => [
+            'SingleLogoutService' => [
+                0 => [
+                    'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
+                    'Location' => 'https://pc-example.org.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/singleLogoutService/default-sp',
+                ],
+            ],
+            'AssertionConsumerService' => [
+                0 => [
+                    'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',
+                    'Location' => 'https://pc-example.org.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/assertionConsumerService/default-sp',
+                    'index' => 0,
+                ],
+                1 => [
+                    'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact',
+                    'Location' => 'https://pc-example.org.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/assertionConsumerService/default-sp',
+                    'index' => 1,
+                ],
+            ],
+            'contacts' => [
+                0 => [
+                    'emailAddress' => 'example@org.hr',
+                    'givenName' => 'Marko Ivančić',
+                    'contactType' => 'technical',
+                ],
+            ],
+            'entityid' => 'https://pc-example.org.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/metadata.php/default-sp',
+            'metadata-index' => 'https://pc-example.org.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/module.php/saml/sp/metadata.php/default-sp',
+            'metadata-set' => 'saml20-sp-remote',
+        ],
+        'Source' => [
+            'host' => 'localhost.someone.from.hr',
+            'privatekey' => 'key.pem',
+            'certificate' => 'cert.pem',
+            'auth' => 'example-userpass',
+            'attributes.NameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri',
+            'authproc' => [100 => ['class' => 'core:AttributeMap', 0 => 'name2oid',],],
+            'entityid' => 'https://localhost.someone.from.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/saml2/idp/metadata.php',
+            'metadata-index' => 'https://localhost.someone.from.hr:9074/simplesamlphp/simplesamlphp-2-beta-git/saml2/idp/metadata.php',
+            'metadata-set' => 'saml20-idp-hosted',
+        ],
+        '\\SimpleSAML\\Auth\\ProcessingChain.filters' => [],
+    ];
+}
diff --git a/tests/src/Entities/Activity/BagTest.php b/tests/src/Entities/Activity/BagTest.php
new file mode 100644
index 0000000..023dcf5
--- /dev/null
+++ b/tests/src/Entities/Activity/BagTest.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Entities\Activity;
+
+use SimpleSAML\Module\accounting\Entities\Activity;
+use SimpleSAML\Module\accounting\Entities\Activity\Bag;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Entities\Activity\Bag
+ */
+class BagTest extends TestCase
+{
+    public function testCanAddActivity(): void
+    {
+        $activityStub = $this->createStub(Activity::class);
+        $bag = new Bag();
+
+        $this->assertEmpty($bag->getAll());
+
+        /** @psalm-suppress InvalidArgument */
+        $bag->add($activityStub);
+
+        $this->assertNotEmpty($bag->getAll());
+    }
+}
diff --git a/tests/src/Entities/ActivityTest.php b/tests/src/Entities/ActivityTest.php
new file mode 100644
index 0000000..2a35bd2
--- /dev/null
+++ b/tests/src/Entities/ActivityTest.php
@@ -0,0 +1,51 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Entities;
+
+use SimpleSAML\Module\accounting\Entities\Activity;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Entities\ServiceProvider;
+use SimpleSAML\Module\accounting\Entities\User;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Entities\Activity
+ */
+class ActivityTest extends TestCase
+{
+    /**
+     * @var \PHPUnit\Framework\MockObject\Stub|ServiceProvider|ServiceProvider&\PHPUnit\Framework\MockObject\Stub
+     */
+    protected $serviceProviderStub;
+    /**
+     * @var \PHPUnit\Framework\MockObject\Stub|User|User&\PHPUnit\Framework\MockObject\Stub
+     */
+    protected $userStub;
+    protected \DateTimeImmutable $happenedAt;
+    protected string $clientIpAddress;
+
+    public function setUp(): void
+    {
+        $this->serviceProviderStub = $this->createStub(ServiceProvider::class);
+        $this->userStub = $this->createStub(User::class);
+        $this->happenedAt = new \DateTimeImmutable();
+        $this->clientIpAddress = '123.123.123.123';
+    }
+
+    public function testCanCreateInstance(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $activity = new Activity(
+            $this->serviceProviderStub,
+            $this->userStub,
+            $this->happenedAt,
+            $this->clientIpAddress
+        );
+
+        $this->assertSame($this->serviceProviderStub, $activity->getServiceProvider());
+        $this->assertSame($this->userStub, $activity->getUser());
+        $this->assertSame($this->happenedAt, $activity->getHappenedAt());
+        $this->assertSame($this->clientIpAddress, $activity->getClientIpAddress());
+    }
+}
diff --git a/tests/src/Entities/Authentication/Event/JobTest.php b/tests/src/Entities/Authentication/Event/JobTest.php
new file mode 100644
index 0000000..a43e3bf
--- /dev/null
+++ b/tests/src/Entities/Authentication/Event/JobTest.php
@@ -0,0 +1,46 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Entities\Authentication\Event;
+
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event\Job;
+use SimpleSAML\Module\accounting\Entities\Authentication\State;
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload;
+use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Entities\Authentication\Event\Job
+ * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractJob
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Event
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\State
+ * @uses \SimpleSAML\Module\accounting\Helpers\NetworkHelper
+ * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
+ */
+class JobTest extends TestCase
+{
+    public function testCanCreateInstanceWithAuthenticationEventEntity(): void
+    {
+        $job = new Job(new Event(new State(StateArrays::FULL)));
+
+        $this->assertInstanceOf(Event::class, $job->getPayload());
+    }
+
+    public function testPayloadMustBeAuthenticationEventOrThrow(): void
+    {
+        $payload = new class extends AbstractPayload {
+        };
+
+        $this->expectException(UnexpectedValueException::class);
+
+        (new Job($payload));
+    }
+
+    public function testCanGetProperType(): void
+    {
+        $job = new Job(new Event(new State(StateArrays::FULL)));
+
+        $this->assertSame(Job::class, $job->getType());
+    }
+}
diff --git a/tests/src/Entities/Authentication/EventTest.php b/tests/src/Entities/Authentication/EventTest.php
new file mode 100644
index 0000000..58b0634
--- /dev/null
+++ b/tests/src/Entities/Authentication/EventTest.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Entities\Authentication;
+
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event;
+use SimpleSAML\Module\accounting\Entities\Authentication\State;
+use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Entities\Authentication\Event
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\State
+ * @uses \SimpleSAML\Module\accounting\Helpers\NetworkHelper
+ * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
+ */
+class EventTest extends TestCase
+{
+    public function testCanGetState(): void
+    {
+        $dateTime = new \DateTimeImmutable();
+        $authenticationEvent = new Event(new State(StateArrays::FULL), $dateTime);
+
+        $this->assertInstanceOf(State::class, $authenticationEvent->getState());
+
+        $this->assertSame(
+            StateArrays::FULL['Source']['entityid'],
+            $authenticationEvent->getState()->getIdentityProviderEntityId()
+        );
+
+        $this->assertEquals($dateTime, $authenticationEvent->getHappenedAt());
+    }
+}
diff --git a/tests/src/Entities/Authentication/StateTest.php b/tests/src/Entities/Authentication/StateTest.php
new file mode 100644
index 0000000..5be1a12
--- /dev/null
+++ b/tests/src/Entities/Authentication/StateTest.php
@@ -0,0 +1,188 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Entities\Authentication;
+
+use SimpleSAML\Module\accounting\Entities\Authentication\State;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Entities\Authentication\State
+ * @uses \SimpleSAML\Module\accounting\Helpers\NetworkHelper
+ * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
+ */
+class StateTest extends TestCase
+{
+    public function testCanInitializeValidState(): void
+    {
+        $state = new State(StateArrays::FULL);
+
+        $this->assertSame($state->getIdentityProviderEntityId(), StateArrays::FULL['Source']['entityid']);
+    }
+
+    public function testCanResolveIdpEntityId(): void
+    {
+        $stateArray = StateArrays::FULL;
+        $state = new State($stateArray);
+        $this->assertSame($state->getIdentityProviderEntityId(), StateArrays::FULL['IdPMetadata']['entityid']);
+
+        $this->expectException(UnexpectedValueException::class);
+        unset($stateArray['IdPMetadata']['entityid']);
+        new State($stateArray);
+    }
+
+    public function testCanResolveSpEntityId(): void
+    {
+        $stateArray = StateArrays::FULL;
+        $state = new State($stateArray);
+        $this->assertSame($state->getServiceProviderEntityId(), StateArrays::FULL['SPMetadata']['entityid']);
+
+        $this->expectException(UnexpectedValueException::class);
+        unset($stateArray['SPMetadata']['entityid']);
+        new State($stateArray);
+    }
+
+    public function testCanResolveAttributes(): void
+    {
+        $state = new State(StateArrays::FULL);
+        $this->assertSame($state->getAttributes(), StateArrays::FULL['Attributes']);
+    }
+
+    public function testCanResolveAccountedClientIpAddress(): void
+    {
+        $stateArray = StateArrays::FULL;
+
+        $state = new State($stateArray);
+        $this->assertNull($state->getClientIpAddress());
+
+        $sampleIp = '123.123.123.123';
+        $stateArray[State::KEY_ACCOUNTING][State::ACCOUNTING_KEY_CLIENT_IP_ADDRESS] = $sampleIp;
+
+        $state = new State($stateArray);
+        $this->assertSame($sampleIp, $state->getClientIpAddress());
+    }
+
+    public function testReturnsNullIfAuthnInstantNotPresent(): void
+    {
+        $stateArray = StateArrays::FULL;
+
+        unset($stateArray['AuthnInstant']);
+
+        $state = new State($stateArray);
+
+        $this->assertNull($state->getAuthenticationInstant());
+    }
+
+    public function testThrowsOnMissingSourceEntityId(): void
+    {
+        $this->expectException(UnexpectedValueException::class);
+
+        $stateArray = StateArrays::FULL;
+
+        unset($stateArray['Source'], $stateArray['IdPMetadata']);
+
+        /** @psalm-suppress UnusedMethodCall */
+        (new State($stateArray));
+    }
+
+    public function testUseSpMetadataForEntityIdIfDestinationNotAvailable(): void
+    {
+        $stateArray = StateArrays::FULL;
+
+        unset($stateArray['Destination']);
+
+        $state = new State($stateArray);
+
+        $this->assertSame($state->getServiceProviderEntityId(), StateArrays::FULL['SPMetadata']['entityid']);
+    }
+
+    public function testThrowsOnMissingDestinationEntityId(): void
+    {
+        $this->expectException(UnexpectedValueException::class);
+
+        $stateArray = StateArrays::FULL;
+
+        unset($stateArray['Destination'], $stateArray['SPMetadata']);
+
+        (new State($stateArray));
+    }
+
+    public function testThrowsOnInvalidAuthnInstantValue(): void
+    {
+        $this->expectException(UnexpectedValueException::class);
+
+        $stateArray = StateArrays::FULL;
+        $stateArray['AuthnInstant'] = 'invalid';
+
+        new State($stateArray);
+    }
+
+    public function testThrowsOnMissingAttributes(): void
+    {
+        $this->expectException(UnexpectedValueException::class);
+
+        $stateArray = StateArrays::FULL;
+
+        unset($stateArray['Attributes']);
+
+        /** @psalm-suppress UnusedMethodCall */
+        (new State($stateArray));
+    }
+
+    public function testCanGetAttributeValue(): void
+    {
+        $state = new State(StateArrays::FULL);
+
+        $this->assertSame(
+            StateArrays::FULL['Attributes']['hrEduPersonUniqueID'][0],
+            $state->getAttributeValue('hrEduPersonUniqueID')
+        );
+
+        $this->assertNull($state->getAttributeValue('non-existent'));
+    }
+
+    public function testCanResolveIdpMetadataArray(): void
+    {
+        // Metadata from 'IdPMetadata'
+        $sampleState = StateArrays::FULL;
+        $state = new State($sampleState);
+        $this->assertEquals($sampleState['IdPMetadata'], $state->getIdentityProviderMetadata());
+
+        // Fallback metadata from 'Source'
+        unset($sampleState['IdPMetadata']);
+        $state = new State($sampleState);
+        $this->assertEquals($sampleState['Source'], $state->getIdentityProviderMetadata());
+
+        // Throws on no IdP metadata
+        $this->expectException(UnexpectedValueException::class);
+        unset($sampleState['Source']);
+        new State($sampleState);
+    }
+
+    public function testCanResolveSpMetadataArray(): void
+    {
+        // Metadata from 'IdPMetadata'
+        $sampleState = StateArrays::FULL;
+        $state = new State($sampleState);
+        $this->assertEquals($sampleState['SPMetadata'], $state->getServiceProviderMetadata());
+
+        // Fallback metadata from 'Destination'
+        unset($sampleState['SPMetadata']);
+        $state = new State($sampleState);
+        $this->assertEquals($sampleState['Destination'], $state->getServiceProviderMetadata());
+
+        // Throws on no SP metadata
+        $this->expectException(UnexpectedValueException::class);
+        unset($sampleState['Destination']);
+        new State($sampleState);
+    }
+
+    public function testCanGetCreatedAt(): void
+    {
+        $state = new State(StateArrays::FULL);
+        $this->assertInstanceOf(\DateTimeImmutable::class, $state->getCreatedAt());
+    }
+}
diff --git a/tests/src/Entities/Bases/AbstractJobTest.php b/tests/src/Entities/Bases/AbstractJobTest.php
new file mode 100644
index 0000000..22725b8
--- /dev/null
+++ b/tests/src/Entities/Bases/AbstractJobTest.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Entities\Bases;
+
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractJob;
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Entities\Bases\AbstractJob
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Event\Job
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Event
+ */
+class AbstractJobTest extends TestCase
+{
+    protected AbstractPayload $payload;
+
+    protected function setUp(): void
+    {
+        $this->payload = new class extends AbstractPayload {
+        };
+    }
+
+    public function testCanInitializeProperties(): void
+    {
+        $id = 1;
+        $createdAt = new \DateTimeImmutable();
+        $job = new class ($this->payload, $id, $createdAt) extends AbstractJob  {
+            public function getType(): string
+            {
+                return self::class;
+            }
+        };
+
+        $this->assertSame($id, $job->getId());
+        $this->assertSame($createdAt, $job->getCreatedAt());
+        $this->assertSame(get_class($job), $job->getType());
+        $this->assertInstanceOf(AbstractPayload::class, $job->getPayload());
+    }
+}
diff --git a/tests/src/Entities/Bases/AbstractProviderTest.php b/tests/src/Entities/Bases/AbstractProviderTest.php
new file mode 100644
index 0000000..f888d23
--- /dev/null
+++ b/tests/src/Entities/Bases/AbstractProviderTest.php
@@ -0,0 +1,95 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Entities\Bases;
+
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Entities\IdentityProvider;
+use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider
+ * @uses \SimpleSAML\Module\accounting\Entities\IdentityProvider
+ */
+class AbstractProviderTest extends TestCase
+{
+    /**
+     * @var array
+     */
+    protected array $metadata;
+
+    public function setUp(): void
+    {
+        $this->metadata = [
+            AbstractProvider::METADATA_KEY_ENTITY_ID => 'http//example.org/idp',
+            AbstractProvider::METADATA_KEY_NAME => [
+                'en' => 'Example service',
+            ],
+            AbstractProvider::METADATA_KEY_DESCRIPTION => [
+                'en' => 'Example description'
+            ],
+        ];
+    }
+
+    /**
+     * @psalm-suppress MixedArrayAccess
+     */
+    public function testCanCreateInstance(): void
+    {
+        $identityProvider = new IdentityProvider($this->metadata);
+
+        $this->assertSame($this->metadata, $identityProvider->getMetadata());
+        $this->assertSame(
+            $this->metadata[AbstractProvider::METADATA_KEY_ENTITY_ID],
+            $identityProvider->getEntityId()
+        );
+        $this->assertSame(
+            $this->metadata[AbstractProvider::METADATA_KEY_NAME]['en'],
+            $identityProvider->getName()
+        );
+        $this->assertSame(
+            $this->metadata[AbstractProvider::METADATA_KEY_DESCRIPTION]['en'],
+            $identityProvider->getDescription()
+        );
+    }
+
+    public function testCanResolveNonLocalizedString(): void
+    {
+        $metadata = $this->metadata;
+        $metadata[AbstractProvider::METADATA_KEY_DESCRIPTION] = 'Non localized description.';
+
+        $identityProvider = new IdentityProvider($metadata);
+
+        $this->assertSame($metadata[AbstractProvider::METADATA_KEY_DESCRIPTION], $identityProvider->getDescription());
+    }
+
+    public function testInvalidLocalizedDataResolvesToNull(): void
+    {
+        $metadata = $this->metadata;
+        $metadata[AbstractProvider::METADATA_KEY_DESCRIPTION] = false;
+
+        $identityProvider = new IdentityProvider($metadata);
+
+        $this->assertNull($identityProvider->getDescription());
+    }
+
+    public function testReturnsNullIfNameNotAvailable(): void
+    {
+        $metadata = $this->metadata;
+        unset($metadata[AbstractProvider::METADATA_KEY_NAME]);
+
+        $identityProvider = new IdentityProvider($metadata);
+        $this->assertNull($identityProvider->getName());
+    }
+
+    public function testThrowsIfEntityIdNotAvailable(): void
+    {
+        $metadata = $this->metadata;
+        unset($metadata[AbstractProvider::METADATA_KEY_ENTITY_ID]);
+
+        $this->expectException(UnexpectedValueException::class);
+        new IdentityProvider($metadata);
+    }
+}
diff --git a/tests/src/Entities/ConnectedServiceProvider/BagTest.php b/tests/src/Entities/ConnectedServiceProvider/BagTest.php
new file mode 100644
index 0000000..3d62a77
--- /dev/null
+++ b/tests/src/Entities/ConnectedServiceProvider/BagTest.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Entities\ConnectedServiceProvider;
+
+use SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider;
+use SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider\Bag;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider\Bag
+ */
+class BagTest extends TestCase
+{
+    public function testCanAddConnectedService(): void
+    {
+        $connectedServiceProvider = $this->createStub(ConnectedServiceProvider::class);
+        $bag = new Bag();
+
+        $this->assertEmpty($bag->getAll());
+        $bag->addOrReplace($connectedServiceProvider);
+        $this->assertNotEmpty($bag->getAll());
+    }
+}
diff --git a/tests/src/Entities/ConnectedServiceProviderTest.php b/tests/src/Entities/ConnectedServiceProviderTest.php
new file mode 100644
index 0000000..186fb2e
--- /dev/null
+++ b/tests/src/Entities/ConnectedServiceProviderTest.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Entities;
+
+use SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Entities\ServiceProvider;
+use SimpleSAML\Module\accounting\Entities\User;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider
+ */
+class ConnectedServiceProviderTest extends TestCase
+{
+    /**
+     * @var \PHPUnit\Framework\MockObject\Stub|ServiceProvider|ServiceProvider&\PHPUnit\Framework\MockObject\Stub
+     */
+    protected $serviceProviderStub;
+    /**
+     * @var \PHPUnit\Framework\MockObject\Stub|User|User&\PHPUnit\Framework\MockObject\Stub
+     */
+    protected $userStub;
+    protected \DateTimeImmutable $dateTime;
+    protected int $numberOfAuthentications;
+
+    public function setUp(): void
+    {
+        $this->serviceProviderStub = $this->createStub(ServiceProvider::class);
+        $this->userStub = $this->createStub(User::class);
+        $this->dateTime = new \DateTimeImmutable();
+        $this->numberOfAuthentications = 1;
+    }
+
+    public function testCanCreateInstance(): void
+    {
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $connectedServiceProvider = new ConnectedServiceProvider(
+            $this->serviceProviderStub,
+            $this->numberOfAuthentications,
+            $this->dateTime,
+            $this->dateTime,
+            $this->userStub
+        );
+
+        $this->assertSame($this->serviceProviderStub, $connectedServiceProvider->getServiceProvider());
+        $this->assertSame($this->numberOfAuthentications, $connectedServiceProvider->getNumberOfAuthentications());
+        $this->assertSame($this->dateTime, $connectedServiceProvider->getFirstAuthenticationAt());
+        $this->assertSame($this->dateTime, $connectedServiceProvider->getLastAuthenticationAt());
+        $this->assertSame($this->userStub, $connectedServiceProvider->getUser());
+    }
+}
diff --git a/tests/src/Entities/GenericJobTest.php b/tests/src/Entities/GenericJobTest.php
new file mode 100644
index 0000000..11aed48
--- /dev/null
+++ b/tests/src/Entities/GenericJobTest.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Entities;
+
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload;
+use SimpleSAML\Module\accounting\Entities\GenericJob;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Entities\GenericJob
+ * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractJob
+ */
+class GenericJobTest extends TestCase
+{
+    public function testCanGetProperType(): void
+    {
+        $job = new GenericJob($this->createStub(AbstractPayload::class));
+
+        $this->assertSame(GenericJob::class, $job->getType());
+    }
+}
diff --git a/tests/src/Entities/IdentityProviderTest.php b/tests/src/Entities/IdentityProviderTest.php
new file mode 100644
index 0000000..401c926
--- /dev/null
+++ b/tests/src/Entities/IdentityProviderTest.php
@@ -0,0 +1,34 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Entities;
+
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider;
+use SimpleSAML\Module\accounting\Entities\IdentityProvider;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Entities\IdentityProvider
+ * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider
+ */
+class IdentityProviderTest extends TestCase
+{
+    /**
+     * @var string[]
+     */
+    protected array $metadata;
+
+    public function setUp(): void
+    {
+        $this->metadata = [
+            AbstractProvider::METADATA_KEY_ENTITY_ID => 'http//example.org/idp'
+        ];
+    }
+
+    public function testCanCreateInstance(): void
+    {
+        $identityProvider = new IdentityProvider($this->metadata);
+        $this->assertSame($this->metadata, $identityProvider->getMetadata());
+    }
+}
diff --git a/tests/src/Entities/ServiceProviderTest.php b/tests/src/Entities/ServiceProviderTest.php
new file mode 100644
index 0000000..3c95923
--- /dev/null
+++ b/tests/src/Entities/ServiceProviderTest.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Entities;
+
+use SimpleSAML\Module\accounting\Entities\ServiceProvider;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Entities\ServiceProvider
+ * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider
+ */
+class ServiceProviderTest extends TestCase
+{
+    /**
+     * @var string[]
+     */
+    protected array $metadata;
+
+    public function setUp(): void
+    {
+        $this->metadata = [
+            'entityid' => 'http//example.org'
+        ];
+    }
+
+    public function testCanCreateInstance(): void
+    {
+        $serviceProvider = new ServiceProvider($this->metadata);
+        $this->assertSame($this->metadata, $serviceProvider->getMetadata());
+    }
+}
diff --git a/tests/src/Entities/UserTest.php b/tests/src/Entities/UserTest.php
new file mode 100644
index 0000000..2119940
--- /dev/null
+++ b/tests/src/Entities/UserTest.php
@@ -0,0 +1,32 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Entities;
+
+use SimpleSAML\Module\accounting\Entities\User;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Entities\User
+ */
+class UserTest extends TestCase
+{
+    /**
+     * @var string[][]
+     */
+    protected array $attributes;
+
+    protected function setUp(): void
+    {
+        $this->attributes = [
+            'uid' => ['test'],
+        ];
+    }
+
+    public function testCanCreateInstance(): void
+    {
+        $user = new User($this->attributes);
+        $this->assertSame($this->attributes, $user->getAttributes());
+    }
+}
diff --git a/tests/src/Helpers/ArrayHelperTest.php b/tests/src/Helpers/ArrayHelperTest.php
new file mode 100644
index 0000000..204f288
--- /dev/null
+++ b/tests/src/Helpers/ArrayHelperTest.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Helpers;
+
+use SimpleSAML\Module\accounting\Helpers\ArrayHelper;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Helpers\ArrayHelper
+ */
+class ArrayHelperTest extends TestCase
+{
+    public function testCanRecursivelySortByKey(): void
+    {
+        $unsorted = [
+            'b' => [1 => 1, 0 => 0],
+            'a' => [1 => 1, 0 => 0],
+        ];
+
+        $sorted = [
+            'a' => [0 => 0, 1 => 1],
+            'b' => [0 => 0, 1 => 1],
+        ];
+
+        $this->assertNotSame($unsorted, $sorted);
+
+        (new ArrayHelper())->recursivelySortByKey($unsorted);
+
+        $this->assertSame($unsorted, $sorted);
+    }
+}
diff --git a/tests/src/Helpers/AttributesHelperTest.php b/tests/src/Helpers/AttributesHelperTest.php
new file mode 100644
index 0000000..8400b1e
--- /dev/null
+++ b/tests/src/Helpers/AttributesHelperTest.php
@@ -0,0 +1,54 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Helpers;
+
+use SimpleSAML\Module\accounting\Helpers\AttributesHelper;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Helpers\AttributesHelper
+ * @uses \SimpleSAML\Module\accounting\ModuleConfiguration
+ * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
+ */
+class AttributesHelperTest extends TestCase
+{
+    /**
+     * @var string $sspBaseDir Simulated SSP base directory.
+     */
+    protected string $sspBaseDir;
+
+    /**
+     * @var string[]
+     */
+    protected array $mapFiles;
+    protected HelpersManager $helpersManager;
+
+    protected function setUp(): void
+    {
+        $this->sspBaseDir = (new ModuleConfiguration())->getModuleRootDirectory() . DIRECTORY_SEPARATOR . 'tests' .
+            DIRECTORY_SEPARATOR;
+
+        $this->mapFiles = ['test.php', 'test2.php'];
+
+        $this->helpersManager = new HelpersManager();
+    }
+
+    public function testCanLoadAttributeMaps(): void
+    {
+        $fullAttributeMap = $this->helpersManager->getAttributesHelper()
+            ->getMergedAttributeMapForFiles($this->sspBaseDir, $this->mapFiles);
+
+        $this->assertArrayHasKey('mobile', $fullAttributeMap);
+        $this->assertArrayHasKey('phone', $fullAttributeMap);
+    }
+
+    public function testIgnoresNonExistentMaps(): void
+    {
+        $fullAttributeMap = $this->helpersManager->getAttributesHelper()
+            ->getMergedAttributeMapForFiles($this->sspBaseDir, ['invalid.php']);
+
+        $this->assertEmpty($fullAttributeMap);
+    }
+}
diff --git a/tests/src/Helpers/DateTimeHelperTest.php b/tests/src/Helpers/DateTimeHelperTest.php
new file mode 100644
index 0000000..ad82ee7
--- /dev/null
+++ b/tests/src/Helpers/DateTimeHelperTest.php
@@ -0,0 +1,28 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Helpers;
+
+use SimpleSAML\Module\accounting\Helpers\DateTimeHelper;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Helpers\DateTimeHelper
+ */
+class DateTimeHelperTest extends TestCase
+{
+    public function testCanConvertDateIntervalToSeconds(): void
+    {
+        $interval = new \DateInterval('PT10S');
+
+        $this->assertSame(10, (new DateTimeHelper())->convertDateIntervalToSeconds($interval));
+    }
+
+    public function testMinimumIntervalIsOneSecond(): void
+    {
+        $interval = \DateInterval::createFromDateString('-10 seconds'); // Negative interval
+
+        $this->assertSame(1, (new DateTimeHelper())->convertDateIntervalToSeconds($interval));
+    }
+}
diff --git a/tests/src/Helpers/EnvironmentHelperTest.php b/tests/src/Helpers/EnvironmentHelperTest.php
new file mode 100644
index 0000000..c6e95ef
--- /dev/null
+++ b/tests/src/Helpers/EnvironmentHelperTest.php
@@ -0,0 +1,19 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Helpers;
+
+use SimpleSAML\Module\accounting\Helpers\EnvironmentHelper;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Helpers\EnvironmentHelper
+ */
+class EnvironmentHelperTest extends TestCase
+{
+    public function testConfirmIsCli(): void
+    {
+        $this->assertTrue((new EnvironmentHelper())->isCli());
+    }
+}
diff --git a/tests/src/Helpers/FilesystemHelperTest.php b/tests/src/Helpers/FilesystemHelperTest.php
new file mode 100644
index 0000000..e6e76ab
--- /dev/null
+++ b/tests/src/Helpers/FilesystemHelperTest.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Helpers;
+
+use SimpleSAML\Module\accounting\Exceptions\InvalidValueException;
+use SimpleSAML\Module\accounting\Helpers\FilesystemHelper;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Helpers\FilesystemHelper
+ */
+class FilesystemHelperTest extends TestCase
+{
+    public function testCanGetRealPath(): void
+    {
+        $path = __DIR__ . DIRECTORY_SEPARATOR . '..';
+
+        $realPath = (new FilesystemHelper())->getRealPath($path);
+
+        $this->assertSame(dirname(__DIR__), $realPath);
+    }
+
+    public function testGetRealPathThrowsOnInvalidPaths(): void
+    {
+        $path = __DIR__ . DIRECTORY_SEPARATOR . 'invalid';
+
+        $this->expectException(InvalidValueException::class);
+
+        (new FilesystemHelper())->getRealPath($path);
+    }
+}
diff --git a/tests/src/Helpers/HashHelperTest.php b/tests/src/Helpers/HashHelperTest.php
new file mode 100644
index 0000000..e0e620a
--- /dev/null
+++ b/tests/src/Helpers/HashHelperTest.php
@@ -0,0 +1,63 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Helpers;
+
+use SimpleSAML\Module\accounting\Helpers\ArrayHelper;
+use SimpleSAML\Module\accounting\Helpers\HashHelper;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Helpers\HashHelper
+ * @uses \SimpleSAML\Module\accounting\Helpers\ArrayHelper
+ */
+class HashHelperTest extends TestCase
+{
+    protected HashHelper $hashHelper;
+
+    protected string $data;
+    protected string $dataSha256;
+    /**
+     * @var \int[][]
+     */
+    protected array $unsortedArrayData;
+    protected string $unsortedArraySha256;
+    /**
+     * @var \int[][]
+     */
+    protected array $sortedArrayData;
+    protected string $sortedArrayDataSha256;
+
+    protected function setUp(): void
+    {
+        $this->hashHelper = new HashHelper(new ArrayHelper());
+
+        $this->data = 'test';
+        $this->dataSha256 = '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08';
+        $this->unsortedArrayData = ['b' => [1 => 1, 0 => 0,], 'a' => [1 => 1, 0 => 0,],];
+        $this->unsortedArraySha256 = 'c467191ddddcaa5a6cc3bac28c1fd0557eb9390dbb079195a2ae70c49ce62da7';
+        $this->sortedArrayData = ['a' => [0 => 0, 1 => 1,], 'b' => [0 => 0, 1 => 1,],];
+        $this->sortedArrayDataSha256 = 'c467191ddddcaa5a6cc3bac28c1fd0557eb9390dbb079195a2ae70c49ce62da7';
+    }
+
+    public function testCanGetSha256ForString(): void
+    {
+        $this->assertSame($this->dataSha256, $this->hashHelper->getSha256($this->data));
+    }
+
+    public function testCanGetSha256ForArray(): void
+    {
+        // Arrays are sorted before the hash is calculated, so the value must be the same.
+        $this->assertSame($this->unsortedArraySha256, $this->sortedArrayDataSha256);
+        $this->assertSame(
+            $this->unsortedArraySha256,
+            $this->hashHelper->getSha256ForArray($this->unsortedArrayData)
+        );
+        $this->assertSame(
+            $this->sortedArrayDataSha256,
+            $this->hashHelper->getSha256ForArray($this->sortedArrayData)
+        );
+    }
+}
diff --git a/tests/src/Helpers/InstanceBuilderUsingModuleConfigurationHelperTest.php b/tests/src/Helpers/InstanceBuilderUsingModuleConfigurationHelperTest.php
new file mode 100644
index 0000000..63345ed
--- /dev/null
+++ b/tests/src/Helpers/InstanceBuilderUsingModuleConfigurationHelperTest.php
@@ -0,0 +1,65 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Helpers;
+
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Module\accounting\Exceptions\Exception;
+use SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfigurationHelper;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Interfaces\BuildableUsingModuleConfigurationInterface;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfigurationHelper
+ */
+class InstanceBuilderUsingModuleConfigurationHelperTest extends TestCase
+{
+    protected BuildableUsingModuleConfigurationInterface $stub;
+    /** @var class-string */
+    protected string $stubClass;
+    protected \PHPUnit\Framework\MockObject\Stub $moduleConfigurationStub;
+    protected \PHPUnit\Framework\MockObject\Stub $loggerStub;
+
+    protected function setUp(): void
+    {
+        $this->stub = new class () implements BuildableUsingModuleConfigurationInterface {
+            public static function build(
+                ModuleConfiguration $moduleConfiguration,
+                LoggerInterface $logger
+            ): BuildableUsingModuleConfigurationInterface {
+                return new self();
+            }
+        };
+
+        $this->stubClass = get_class($this->stub);
+
+        $this->moduleConfigurationStub = $this->createStub(ModuleConfiguration::class);
+        $this->loggerStub = $this->createStub(LoggerInterface::class);
+    }
+
+    public function testCanBuildClassInstance(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $this->assertInstanceOf(
+            BuildableUsingModuleConfigurationInterface::class,
+            (new InstanceBuilderUsingModuleConfigurationHelper())->build(
+                $this->stubClass,
+                $this->moduleConfigurationStub,
+                $this->loggerStub
+            )
+        );
+    }
+
+    public function testThrowsForInvalidClass(): void
+    {
+        $this->expectException(Exception::class);
+
+        /** @psalm-suppress InvalidArgument */
+        (new InstanceBuilderUsingModuleConfigurationHelper())->build(
+            ModuleConfiguration::class, // Sample class which is not buildable.
+            $this->moduleConfigurationStub,
+            $this->loggerStub
+        );
+    }
+}
diff --git a/tests/src/Helpers/ModuleRoutesHelperTest.php b/tests/src/Helpers/ModuleRoutesHelperTest.php
new file mode 100644
index 0000000..aa07c47
--- /dev/null
+++ b/tests/src/Helpers/ModuleRoutesHelperTest.php
@@ -0,0 +1,56 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Helpers;
+
+use SimpleSAML\Module\accounting\Helpers\ModuleRoutesHelper;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Utils\HTTP;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Helpers\ModuleRoutesHelper
+ */
+class ModuleRoutesHelperTest extends TestCase
+{
+    protected const BASE_URL = 'https://example.org/ssp/';
+    /**
+     * @var \PHPUnit\Framework\MockObject\Stub|HTTP
+     */
+    protected $sspHttpUtilsStub;
+    protected string $moduleUrl;
+
+    protected function setUp(): void
+    {
+        $this->sspHttpUtilsStub = $this->createStub(HTTP::class);
+        $this->sspHttpUtilsStub->method('getBaseURL')->willReturn(self::BASE_URL);
+
+        $this->moduleUrl = self::BASE_URL . 'module.php/' . ModuleConfiguration::MODULE_NAME;
+    }
+
+    public function testCanGetModuleUrl(): void
+    {
+        $path = 'sample-path';
+        $moduleUrlWithPath = $this->moduleUrl . '/' . $path;
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $moduleRoutesHelper = new ModuleRoutesHelper($this->sspHttpUtilsStub);
+
+        $this->assertSame($moduleUrlWithPath, $moduleRoutesHelper->getUrl($path));
+    }
+
+    public function testCanCallMethodToAddParamsToModuleUrl(): void
+    {
+        $path = 'sample-path';
+        $params = ['sample' => 'param'];
+        $fullUrl = 'full-url-with-sample-param';
+
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->sspHttpUtilsStub->method('addURLParameters')->willReturn($fullUrl);
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $moduleRoutesHelper = new ModuleRoutesHelper($this->sspHttpUtilsStub);
+
+        $this->assertSame($fullUrl, $moduleRoutesHelper->getUrl($path, $params));
+    }
+}
diff --git a/tests/src/Helpers/NetworkHelperTest.php b/tests/src/Helpers/NetworkHelperTest.php
new file mode 100644
index 0000000..98cfed2
--- /dev/null
+++ b/tests/src/Helpers/NetworkHelperTest.php
@@ -0,0 +1,48 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Helpers;
+
+use SimpleSAML\Module\accounting\Helpers\NetworkHelper;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Helpers\NetworkHelper
+ */
+class NetworkHelperTest extends TestCase
+{
+    protected string $ipAddress;
+
+    protected function setUp(): void
+    {
+        $this->ipAddress = '123.123.123.123';
+    }
+
+    public function testCanGetIpFromParameter(): void
+    {
+        $this->assertSame($this->ipAddress, (new NetworkHelper())->resolveClientIpAddress($this->ipAddress));
+    }
+
+    public function testReturnsNullForInvalidIp(): void
+    {
+        $this->assertNull((new NetworkHelper())->resolveClientIpAddress('invalid'));
+    }
+
+    public function testReturnsNullForNonExistentIp(): void
+    {
+        $this->assertNull((new NetworkHelper())->resolveClientIpAddress());
+    }
+
+    /**
+     * @backupGlobals enabled
+     */
+    public function testCanResolveIpAddress(): void
+    {
+        global $_SERVER;
+
+        $_SERVER['REMOTE_ADDR'] = $this->ipAddress;
+
+        $this->assertSame($this->ipAddress, (new NetworkHelper())->resolveClientIpAddress());
+    }
+}
diff --git a/tests/src/Helpers/RandomHelperTest.php b/tests/src/Helpers/RandomHelperTest.php
new file mode 100644
index 0000000..538b313
--- /dev/null
+++ b/tests/src/Helpers/RandomHelperTest.php
@@ -0,0 +1,17 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Helpers;
+
+use SimpleSAML\Module\accounting\Helpers\RandomHelper;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Helpers\RandomHelper
+ */
+class RandomHelperTest extends TestCase
+{
+    public function testCanGetRandomInt(): void
+    {
+        $this->assertIsInt((new RandomHelper())->getRandomInt());
+    }
+}
diff --git a/tests/src/ModuleConfigurationTest.php b/tests/src/ModuleConfigurationTest.php
new file mode 100644
index 0000000..50bc222
--- /dev/null
+++ b/tests/src/ModuleConfigurationTest.php
@@ -0,0 +1,352 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting;
+
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Configuration;
+use SimpleSAML\Module\accounting\Exceptions\InvalidConfigurationException;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Stores;
+use SimpleSAML\Module\accounting\Trackers;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\ModuleConfiguration
+ */
+class ModuleConfigurationTest extends TestCase
+{
+    protected ModuleConfiguration $moduleConfiguration;
+
+    protected function setUp(): void
+    {
+        parent::setUp();
+        // Configuration directory is set by phpunit using php ENV setting feature (check phpunit.xml).
+        $this->moduleConfiguration = new ModuleConfiguration('module_accounting.php');
+    }
+
+    public function testCanGetUnderlyingConfigurationInstance(): void
+    {
+        $this->assertInstanceOf(Configuration::class, $this->moduleConfiguration->getConfiguration());
+    }
+
+    public function testThrowExceptionsIfInvalidOptionIsSupplied(): void
+    {
+        $this->expectException(InvalidConfigurationException::class);
+
+        $this->moduleConfiguration->get('invalid');
+    }
+
+    public function testCanGetValidOption(): void
+    {
+        $this->assertIsString($this->moduleConfiguration->get(ModuleConfiguration::OPTION_USER_ID_ATTRIBUTE_NAME));
+    }
+
+    public function testCanGetUserIdAttributeName(): void
+    {
+        $this->assertIsString($this->moduleConfiguration->getUserIdAttributeName());
+    }
+
+    public function testCanGetDefaultAuthenticationSource(): void
+    {
+        $this->assertIsString($this->moduleConfiguration->getDefaultAuthenticationSource());
+    }
+
+    public function testCanGetJobsStoreClass(): void
+    {
+        $this->assertTrue(
+            is_subclass_of($this->moduleConfiguration->getJobsStoreClass(), Stores\Interfaces\JobsStoreInterface::class)
+        );
+    }
+
+    public function testThrowsForInvalidConfig(): void
+    {
+        $this->expectException(InvalidConfigurationException::class);
+
+        new ModuleConfiguration(
+            null,
+            [
+                ModuleConfiguration::OPTION_ACCOUNTING_PROCESSING_TYPE => 'invalid',
+            ]
+        );
+    }
+
+    public function testThrowsForInvalidJobsStore(): void
+    {
+        $this->expectException(InvalidConfigurationException::class);
+
+        new ModuleConfiguration(
+            null,
+            [
+                ModuleConfiguration::OPTION_ACCOUNTING_PROCESSING_TYPE =>
+                    ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS,
+                ModuleConfiguration::OPTION_JOBS_STORE => 'invalid',
+            ]
+        );
+    }
+
+    public function testProperConnectionKeyIsReturned(): void
+    {
+        $this->assertSame(
+            'doctrine_dbal_pdo_sqlite',
+            $this->moduleConfiguration->getClassConnectionKey(Stores\Jobs\DoctrineDbal\Store::class)
+        );
+    }
+
+    public function testCanGetSlaveConnectionKey(): void
+    {
+        $this->assertSame(
+            'doctrine_dbal_pdo_sqlite_slave',
+            $this->moduleConfiguration->getClassConnectionKey(
+                Trackers\Authentication\DoctrineDbal\Versioned\Tracker::class,
+                ModuleConfiguration\ConnectionType::SLAVE
+            )
+        );
+    }
+
+    public function testThrowsForNonStringAndNonArrayConnectionKey(): void
+    {
+        $this->expectException(InvalidConfigurationException::class);
+
+        new ModuleConfiguration(
+            null,
+            [
+                ModuleConfiguration::OPTION_CLASS_TO_CONNECTION_MAP => [
+                    'invalid-object-value' => new \stdClass(),
+                ]
+            ]
+        );
+    }
+
+    public function testThrowsForNonMasterInArrayConnection(): void
+    {
+        $this->expectException(InvalidConfigurationException::class);
+
+        new ModuleConfiguration(
+            null,
+            [
+                ModuleConfiguration::OPTION_CLASS_TO_CONNECTION_MAP => [
+                    'invalid-array-value' => [
+                        'no-master-key' => 'invalid',
+                    ],
+                ]
+            ]
+        );
+    }
+
+    public function testThrowsForInvalidConnectiontype(): void
+    {
+        $this->expectException(InvalidConfigurationException::class);
+
+        $this->moduleConfiguration->getClassConnectionKey(
+            Stores\Jobs\DoctrineDbal\Store::class,
+            'invalid'
+        );
+    }
+
+    public function testInvalidConnectionKeyThrows(): void
+    {
+        $this->expectException(InvalidConfigurationException::class);
+
+        $this->moduleConfiguration->getClassConnectionParameters('invalid');
+    }
+
+    public function testCanGetDefinedConnections(): void
+    {
+        $this->assertArrayHasKey(
+            'doctrine_dbal_pdo_sqlite',
+            $this->moduleConfiguration->getConnectionsAndParameters()
+        );
+    }
+
+    public function testCanGetParametersForSpecificConnection(): void
+    {
+        $this->assertIsArray($this->moduleConfiguration->getConnectionParameters('doctrine_dbal_pdo_sqlite'));
+    }
+
+    public function testGettingSettingsForInvalidConnectionThrows(): void
+    {
+        $this->expectException(InvalidConfigurationException::class);
+        $this->moduleConfiguration->getConnectionParameters('invalid');
+    }
+
+    public function testCanGetModuleSourceDirectory(): void
+    {
+        $this->assertSame(
+            dirname(__DIR__, 2) . DIRECTORY_SEPARATOR .  'src',
+            $this->moduleConfiguration->getModuleSourceDirectory()
+        );
+    }
+
+    public function testCanGetModuleRootDirectory(): void
+    {
+        $this->assertSame(
+            dirname(__DIR__, 2),
+            $this->moduleConfiguration->getModuleRootDirectory()
+        );
+    }
+
+    public function testCanGetCronTagForJobRunner(): void
+    {
+        $this->assertSame(
+            'accounting_job_runner',
+            $this->moduleConfiguration->getCronTagForJobRunner()
+        );
+    }
+
+    public function testCanGetJobRunnerMaximumExecutionTime(): void
+    {
+        $this->assertNull($this->moduleConfiguration->getJobRunnerMaximumExecutionTime());
+    }
+
+    public function testThrowsForNonStringJobRunnerMaximumExecutionTime(): void
+    {
+        $moduleConfiguration = new ModuleConfiguration(
+            null,
+            [ModuleConfiguration::OPTION_JOB_RUNNER_MAXIMUM_EXECUTION_TIME => false]
+        );
+
+        $this->expectException(InvalidConfigurationException::class);
+
+        $moduleConfiguration->getJobRunnerMaximumExecutionTime();
+    }
+
+    public function testThrowsForInvalidStringJobRunnerMaximumExecutionTime(): void
+    {
+        $moduleConfiguration = new ModuleConfiguration(
+            null,
+            [ModuleConfiguration::OPTION_JOB_RUNNER_MAXIMUM_EXECUTION_TIME => 'invalid']
+        );
+
+
+        $this->expectException(InvalidConfigurationException::class);
+
+        $moduleConfiguration->getJobRunnerMaximumExecutionTime();
+    }
+
+    public function testCanGetJobRunnerShouldPauseAfterNumberOfJobsProcessed(): void
+    {
+        $this->assertSame(10, $this->moduleConfiguration->getJobRunnerShouldPauseAfterNumberOfJobsProcessed());
+    }
+
+    public function testCanGetNullForJobRunnerShouldPauseAfterNumberOfJobsProcessed(): void
+    {
+        $moduleConfiguration = new ModuleConfiguration(
+            null,
+            [ModuleConfiguration::OPTION_JOB_RUNNER_SHOULD_PAUSE_AFTER_NUMBER_OF_JOBS_PROCESSED => null]
+        );
+
+        $this->assertNull($moduleConfiguration->getJobRunnerShouldPauseAfterNumberOfJobsProcessed());
+    }
+
+    public function testThrowsForNonIntegerJobRunnerShouldPauseAfterNumberOfJobsProcessed(): void
+    {
+        $moduleConfiguration = new ModuleConfiguration(
+            null,
+            [ModuleConfiguration::OPTION_JOB_RUNNER_SHOULD_PAUSE_AFTER_NUMBER_OF_JOBS_PROCESSED => false]
+        );
+
+        $this->expectException(InvalidConfigurationException::class);
+
+        $moduleConfiguration->getJobRunnerShouldPauseAfterNumberOfJobsProcessed();
+    }
+
+    public function testThrowsForNegativeIntegerJobRunnerShouldPauseAfterNumberOfJobsProcessed(): void
+    {
+        $moduleConfiguration = new ModuleConfiguration(
+            null,
+            [ModuleConfiguration::OPTION_JOB_RUNNER_SHOULD_PAUSE_AFTER_NUMBER_OF_JOBS_PROCESSED => -1]
+        );
+
+        $this->expectException(InvalidConfigurationException::class);
+
+        $moduleConfiguration->getJobRunnerShouldPauseAfterNumberOfJobsProcessed();
+    }
+
+    public function testThrowsOnInvalidCronTag(): void
+    {
+        $this->expectException(InvalidConfigurationException::class);
+
+        new ModuleConfiguration(
+            null,
+            [
+                ModuleConfiguration::OPTION_ACCOUNTING_PROCESSING_TYPE =>
+                    ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS,
+                ModuleConfiguration::OPTION_CRON_TAG_FOR_JOB_RUNNER => -1
+            ]
+        );
+    }
+
+    public function testThrowsOnInvalidDefaultDataTrackerAndProvider(): void
+    {
+        $this->expectException(InvalidConfigurationException::class);
+
+        new ModuleConfiguration(
+            null,
+            [
+                ModuleConfiguration::OPTION_DEFAULT_DATA_TRACKER_AND_PROVIDER => 'invalid'
+            ]
+        );
+    }
+
+    public function testThrowsOnInvalidAdditionalTrackers(): void
+    {
+        $this->expectException(InvalidConfigurationException::class);
+
+        new ModuleConfiguration(
+            null,
+            [
+                ModuleConfiguration::OPTION_ADDITIONAL_TRACKERS => ['invalid']
+            ]
+        );
+    }
+
+    public function testThrowsOnNonStringAdditionalTracker(): void
+    {
+        $this->expectException(InvalidConfigurationException::class);
+
+        new ModuleConfiguration(
+            null,
+            [
+                ModuleConfiguration::OPTION_ADDITIONAL_TRACKERS => [-1]
+            ]
+        );
+    }
+
+    public function testThrowsWhenClassHasNoConnectionParametersSet(): void
+    {
+        $this->expectException(InvalidConfigurationException::class);
+
+        new ModuleConfiguration(
+            null,
+            [
+                ModuleConfiguration::OPTION_CONNECTIONS_AND_PARAMETERS => []
+            ]
+        );
+    }
+
+    public function testThrowsForInvalidTrackerDataRetentionPolicy(): void
+    {
+        $this->expectException(InvalidConfigurationException::class);
+
+        new ModuleConfiguration(
+            null,
+            [
+                ModuleConfiguration::OPTION_TRACKER_DATA_RETENTION_POLICY => 'invalid'
+            ]
+        );
+    }
+
+    public function testThrowsForInvalidCronTagForTrackerDataRetentionPolicy(): void
+    {
+        $this->expectException(InvalidConfigurationException::class);
+
+        new ModuleConfiguration(
+            null,
+            [
+                ModuleConfiguration::OPTION_TRACKER_DATA_RETENTION_POLICY => 'P1D',
+                ModuleConfiguration::OPTION_CRON_TAG_FOR_TRACKER_DATA_RETENTION_POLICY => false,
+            ]
+        );
+    }
+}
diff --git a/tests/src/Providers/Builders/AuthenticationDataProviderBuilderTest.php b/tests/src/Providers/Builders/AuthenticationDataProviderBuilderTest.php
new file mode 100644
index 0000000..497fd3a
--- /dev/null
+++ b/tests/src/Providers/Builders/AuthenticationDataProviderBuilderTest.php
@@ -0,0 +1,86 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Providers\Builders;
+
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Module\accounting\Exceptions\Exception;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Providers\Builders\AuthenticationDataProviderBuilder;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+use SimpleSAML\Module\accounting\Trackers\Authentication\DoctrineDbal\Versioned\Tracker;
+use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Providers\Builders\AuthenticationDataProviderBuilder
+ * @uses \SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfigurationHelper
+ * @uses \SimpleSAML\Module\accounting\Stores\Builders\Bases\AbstractStoreBuilder
+ * @uses \SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractStore
+ * @uses \SimpleSAML\Module\accounting\Stores\Builders\DataStoreBuilder
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Repository
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Factory
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store
+ * @uses \SimpleSAML\Module\accounting\Trackers\Authentication\DoctrineDbal\Versioned\Tracker
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\Bases\AbstractMigrator
+ * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
+ * @uses \SimpleSAML\Module\accounting\Stores\Bases\AbstractStore
+ */
+class AuthenticationDataProviderBuilderTest extends TestCase
+{
+    protected \PHPUnit\Framework\MockObject\Stub $moduleConfigurationStub;
+
+    protected \PHPUnit\Framework\MockObject\Stub $loggerStub;
+    protected HelpersManager $helpersManager;
+
+    protected function setUp(): void
+    {
+        $this->moduleConfigurationStub = $this->createStub(ModuleConfiguration::class);
+        $connectionParams = ConnectionParameters::DBAL_SQLITE_MEMORY;
+        $this->moduleConfigurationStub->method('getConnectionParameters')
+            ->willReturn($connectionParams);
+
+        $this->loggerStub = $this->createStub(LoggerInterface::class);
+        $this->helpersManager = new HelpersManager();
+    }
+
+    public function testCanCreateInstance(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $this->assertInstanceOf(
+            AuthenticationDataProviderBuilder::class,
+            new AuthenticationDataProviderBuilder(
+                $this->moduleConfigurationStub,
+                $this->loggerStub,
+                $this->helpersManager
+            )
+        );
+    }
+
+    public function testCanBuildDataProvider(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $builder = new AuthenticationDataProviderBuilder(
+            $this->moduleConfigurationStub,
+            $this->loggerStub,
+            $this->helpersManager
+        );
+
+        $this->assertInstanceOf(Tracker::class, $builder->build(Tracker::class));
+    }
+
+    public function testThrowsForInvalidClass(): void
+    {
+        $this->expectException(Exception::class);
+
+        /** @psalm-suppress InvalidArgument */
+        (new AuthenticationDataProviderBuilder(
+            $this->moduleConfigurationStub,
+            $this->loggerStub,
+            $this->helpersManager
+        ))->build('invalid');
+    }
+}
diff --git a/tests/src/Services/HelpersManagerTest.php b/tests/src/Services/HelpersManagerTest.php
new file mode 100644
index 0000000..a199731
--- /dev/null
+++ b/tests/src/Services/HelpersManagerTest.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Services;
+
+use SimpleSAML\Module\accounting\Helpers\ArrayHelper;
+use SimpleSAML\Module\accounting\Helpers\AttributesHelper;
+use SimpleSAML\Module\accounting\Helpers\DateTimeHelper;
+use SimpleSAML\Module\accounting\Helpers\EnvironmentHelper;
+use SimpleSAML\Module\accounting\Helpers\FilesystemHelper;
+use SimpleSAML\Module\accounting\Helpers\HashHelper;
+use SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfigurationHelper;
+use SimpleSAML\Module\accounting\Helpers\ModuleRoutesHelper;
+use SimpleSAML\Module\accounting\Helpers\NetworkHelper;
+use SimpleSAML\Module\accounting\Helpers\RandomHelper;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Services\HelpersManager
+ * @uses \SimpleSAML\Module\accounting\Helpers\ModuleRoutesHelper
+ * @uses \SimpleSAML\Module\accounting\Helpers\HashHelper
+ */
+class HelpersManagerTest extends TestCase
+{
+    public function testCanGetHelperInstances(): void
+    {
+        $helpersManager = new HelpersManager();
+
+        $this->assertInstanceOf(ArrayHelper::class, $helpersManager->getArrayHelper());
+        $this->assertInstanceOf(AttributesHelper::class, $helpersManager->getAttributesHelper());
+        $this->assertInstanceOf(DateTimeHelper::class, $helpersManager->getDateTimeHelper());
+        $this->assertInstanceOf(EnvironmentHelper::class, $helpersManager->getEnvironmentHelper());
+        $this->assertInstanceOf(FilesystemHelper::class, $helpersManager->getFilesystemHelper());
+        $this->assertInstanceOf(HashHelper::class, $helpersManager->getHashHelper());
+        $this->assertInstanceOf(
+            InstanceBuilderUsingModuleConfigurationHelper::class,
+            $helpersManager->getInstanceBuilderUsingModuleConfigurationHelper()
+        );
+        $this->assertInstanceOf(NetworkHelper::class, $helpersManager->getNetworkHelper());
+        $this->assertInstanceOf(RandomHelper::class, $helpersManager->getRandomHelper());
+        $this->assertInstanceOf(ModuleRoutesHelper::class, $helpersManager->getModuleRoutesHelper());
+    }
+}
diff --git a/tests/src/Services/JobRunner/RateLimiterTest.php b/tests/src/Services/JobRunner/RateLimiterTest.php
new file mode 100644
index 0000000..19a98c6
--- /dev/null
+++ b/tests/src/Services/JobRunner/RateLimiterTest.php
@@ -0,0 +1,67 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Services\JobRunner;
+
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Services\JobRunner\RateLimiter;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Services\JobRunner\RateLimiter
+ * @uses \SimpleSAML\Module\accounting\Helpers\DateTimeHelper
+ * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
+ */
+class RateLimiterTest extends TestCase
+{
+    protected function setUp(): void
+    {
+    }
+
+    public function testCanCreateInstance(): void
+    {
+        $this->assertInstanceOf(RateLimiter::class, new RateLimiter());
+    }
+
+    public function testCanDoPause(): void
+    {
+        $rateLimiter = new RateLimiter();
+        $startTimeInSeconds = (new \DateTimeImmutable())->getTimestamp();
+        $rateLimiter->doPause();
+        $endTimeInSeconds = (new \DateTimeImmutable())->getTimestamp();
+
+        $this->assertTrue(($endTimeInSeconds - $startTimeInSeconds) >= 1);
+    }
+
+    public function testCanSetMaxPause(): void
+    {
+        $rateLimiter = new RateLimiter(new \DateInterval('PT1S'));
+        $this->assertSame(1, $rateLimiter->getMaxPauseInSeconds());
+        $splitSecondInterval = \DateInterval::createFromDateString('10000 microsecond'); // 10 milliseconds
+        $rateLimiter = new RateLimiter($splitSecondInterval);
+        $this->assertSame(1, $rateLimiter->getMaxPauseInSeconds());
+        $rateLimiter->doPause();
+    }
+
+    public function testCanDoBackoffPause(): void
+    {
+        $rateLimiter = new RateLimiter();
+        $startTimeInSeconds = (new \DateTimeImmutable())->getTimestamp();
+        $rateLimiter->doBackoffPause();
+        $endTimeInSeconds = (new \DateTimeImmutable())->getTimestamp();
+        $this->assertTrue(($endTimeInSeconds - $startTimeInSeconds) >= 1);
+        $this->assertTrue($rateLimiter->getCurrentBackoffPauseInSeconds() > 1);
+        $rateLimiter->resetBackoffPause();
+        $this->assertTrue($rateLimiter->getCurrentBackoffPauseInSeconds() === 1);
+    }
+
+    public function testCanSetMaxBackoffPause(): void
+    {
+        $rateLimiter = new RateLimiter(null, new \DateInterval('PT1S'));
+        $this->assertSame(1, $rateLimiter->getMaxBackoffPauseInSeconds());
+        $splitSecondInterval = \DateInterval::createFromDateString('10000 microsecond'); // 10 milliseconds
+        $rateLimiter = new \SimpleSAML\Module\accounting\Services\JobRunner\RateLimiter(null, $splitSecondInterval);
+        $this->assertSame(1, $rateLimiter->getMaxBackoffPauseInSeconds());
+        $rateLimiter->doBackoffPause();
+    }
+}
diff --git a/tests/src/Services/JobRunner/StateTest.php b/tests/src/Services/JobRunner/StateTest.php
new file mode 100644
index 0000000..533030e
--- /dev/null
+++ b/tests/src/Services/JobRunner/StateTest.php
@@ -0,0 +1,117 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Services\JobRunner;
+
+use SimpleSAML\Module\accounting\Services\JobRunner\State;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Services\JobRunner\State
+ */
+class StateTest extends TestCase
+{
+    protected int $jobRunnerId;
+
+    protected function setUp(): void
+    {
+        $this->jobRunnerId = 1;
+    }
+
+    public function testCanCreateInstance(): void
+    {
+        $startedAt = $updatedAt = new \DateTimeImmutable();
+
+        $state = new State($this->jobRunnerId);
+        $this->assertInstanceOf(State::class, $state);
+        $this->assertSame($this->jobRunnerId, $state->getJobRunnerId());
+
+        $state = new State($this->jobRunnerId, $startedAt, null);
+        $this->assertInstanceOf(State::class, $state);
+
+        $state = new State($this->jobRunnerId, $startedAt, $updatedAt);
+        $this->assertInstanceOf(State::class, $state);
+
+        $state = new State($this->jobRunnerId, $startedAt, $updatedAt, 1000);
+        $this->assertInstanceOf(State::class, $state);
+    }
+
+    public function testCanWorkWithTimestamps(): void
+    {
+        $startedAt = $updatedAt = $endedAt = new \DateTimeImmutable();
+
+        $state = new State($this->jobRunnerId);
+        $this->assertNull($state->getStartedAt());
+        $this->assertInstanceOf(\DateTimeImmutable::class, $state->getUpdatedAt());
+        $this->assertNull($state->getEndedAt());
+
+        $this->assertTrue($state->setStartedAt($startedAt));
+        $this->assertTrue($state->hasRunStarted());
+        $state->setUpdatedAt($updatedAt);
+        $this->assertTrue($state->setEndedAt($endedAt));
+
+        $this->assertSame($startedAt, $state->getStartedAt());
+        $this->assertSame($updatedAt, $state->getUpdatedAt());
+        $this->assertSame($endedAt, $state->getEndedAt());
+
+        $this->assertFalse($state->setStartedAt($startedAt));
+        $this->assertFalse($state->setEndedAt($endedAt));
+    }
+
+    public function testCanCountProcessedJobs(): void
+    {
+        $state = new State($this->jobRunnerId);
+
+        $this->assertSame(0, $state->getTotalJobsProcessed());
+        $state->incrementSuccessfulJobsProcessed();
+
+        $this->assertSame(1, $state->getTotalJobsProcessed());
+        $this->assertSame(1, $state->getSuccessfulJobsProcessed());
+        $this->assertSame(0, $state->getFailedJobsProcessed());
+
+        $state->incrementFailedJobsProcessed();
+
+        $this->assertSame(2, $state->getTotalJobsProcessed());
+        $this->assertSame(1, $state->getSuccessfulJobsProcessed());
+        $this->assertSame(1, $state->getFailedJobsProcessed());
+    }
+
+    public function testCanCheckIfStateIsStale(): void
+    {
+        $state = new State($this->jobRunnerId);
+        $freshnessDuration = new \DateInterval('PT5M');
+
+        $this->assertFalse($state->isStale($freshnessDuration));
+
+        $dateTimeInHistory = new \DateTimeImmutable('-9 minutes');
+        $state->setUpdatedAt($dateTimeInHistory);
+
+        $this->assertTrue($state->isStale($freshnessDuration));
+    }
+
+    public function testCanWorkWithStatusMessages(): void
+    {
+        $state = new State($this->jobRunnerId, null, null, 2);
+        $this->assertEmpty($state->getStatusMessages());
+        $this->assertNull($state->getLastStatusMessage());
+
+        $state->addStatusMessage('test');
+        $this->assertSame(1, count($state->getStatusMessages()));
+        $this->assertSame('test', $state->getLastStatusMessage());
+        $state->addStatusMessage('test2');
+        $this->assertSame('test2', $state->getLastStatusMessage());
+        $this->assertSame(2, count($state->getStatusMessages()));
+        $state->addStatusMessage('test3');
+        $this->assertSame('test3', $state->getLastStatusMessage());
+        $this->assertSame(2, count($state->getStatusMessages()));
+        $this->assertSame('test3', $state->getLastStatusMessage());
+    }
+
+    public function testCanSetGracefulInterruptInitiatedFlag(): void
+    {
+        $state = new State($this->jobRunnerId);
+
+        $this->assertFalse($state->getIsGracefulInterruptInitiated());
+        $state->setIsGracefulInterruptInitiated(true);
+        $this->assertTrue($state->getIsGracefulInterruptInitiated());
+    }
+}
diff --git a/tests/src/Services/JobRunnerTest.php b/tests/src/Services/JobRunnerTest.php
new file mode 100644
index 0000000..ceddecc
--- /dev/null
+++ b/tests/src/Services/JobRunnerTest.php
@@ -0,0 +1,1085 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Services;
+
+use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\MockObject\Stub;
+use Psr\Log\LoggerInterface;
+use Psr\SimpleCache\CacheInterface;
+use SimpleSAML\Configuration;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event;
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload;
+use SimpleSAML\Module\accounting\Entities\Interfaces\JobInterface;
+use SimpleSAML\Module\accounting\Exceptions\Exception;
+use SimpleSAML\Module\accounting\Helpers\DateTimeHelper;
+use SimpleSAML\Module\accounting\Helpers\EnvironmentHelper;
+use SimpleSAML\Module\accounting\Helpers\RandomHelper;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+use SimpleSAML\Module\accounting\Services\JobRunner;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Stores\Builders\JobsStoreBuilder;
+use SimpleSAML\Module\accounting\Stores\Interfaces\JobsStoreInterface;
+use SimpleSAML\Module\accounting\Trackers\Builders\AuthenticationDataTrackerBuilder;
+use SimpleSAML\Module\accounting\Trackers\Interfaces\AuthenticationDataTrackerInterface;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Services\JobRunner
+ *
+ * @psalm-suppress all
+ */
+class JobRunnerTest extends TestCase
+{
+    /**
+     * @var Stub|ModuleConfiguration
+     */
+    protected $moduleConfigurationStub;
+    /**
+     * @var Stub|Configuration
+     */
+    protected $sspConfigurationStub;
+    /**
+     * @var MockObject|LoggerInterface
+     */
+    protected $loggerMock;
+    /**
+     * @var MockObject|CacheInterface
+     */
+    protected $cacheMock;
+    /**
+     * @var Stub|JobRunner\State
+     */
+    protected $stateStub;
+    /**
+     * @var Stub|JobRunner\RateLimiter
+     */
+    protected $rateLimiterMock;
+    /**
+     * @var Stub|AuthenticationDataTrackerBuilder
+     */
+    protected $authenticationDataTrackerBuilderStub;
+    /**
+     * @var MockObject|AuthenticationDataTrackerInterface
+     */
+    protected $authenticationDataTrackerMock;
+    /**
+     * @var Stub|JobsStoreBuilder
+     */
+    protected $jobsStoreBuilderStub;
+    /**
+     * @var Stub|RandomHelper
+     */
+    protected $randomHelperStub;
+    /**
+     * @var Stub|EnvironmentHelper
+     */
+    protected $environmentHelperStub;
+    /**
+     * @var Stub|DateTimeHelper
+     */
+    protected $dateTimeHelperStub;
+    /**
+     * @var Stub|HelpersManager
+     */
+    protected $helpersManagerStub;
+    /**
+     * @var Stub|JobsStoreInterface
+     */
+    protected $jobsStoreMock;
+    /**
+     * @var Stub|JobInterface
+     */
+    protected $jobStub;
+    /**
+     * @var Stub|AbstractPayload
+     */
+    protected $payloadStub;
+
+    protected function setUp(): void
+    {
+        $this->moduleConfigurationStub = $this->createStub(ModuleConfiguration::class);
+        $this->sspConfigurationStub = $this->createStub(Configuration::class);
+        $this->loggerMock = $this->createMock(LoggerInterface::class);
+        $this->authenticationDataTrackerBuilderStub = $this->createStub(AuthenticationDataTrackerBuilder::class);
+        $this->authenticationDataTrackerMock = $this->createMock(AuthenticationDataTrackerInterface::class);
+        $this->jobsStoreBuilderStub = $this->createStub(JobsStoreBuilder::class);
+        $this->cacheMock = $this->createMock(CacheInterface::class);
+        $this->stateStub = $this->createStub(JobRunner\State::class);
+        $this->rateLimiterMock = $this->createMock(JobRunner\RateLimiter::class);
+        $this->randomHelperStub = $this->createStub(RandomHelper::class);
+        $this->environmentHelperStub = $this->createStub(EnvironmentHelper::class);
+        $this->dateTimeHelperStub = $this->createStub(DateTimeHelper::class);
+        $this->helpersManagerStub = $this->createStub(HelpersManager::class);
+        $this->jobsStoreMock = $this->createMock(JobsStoreInterface::class);
+        $this->jobStub = $this->createStub(JobInterface::class);
+        $this->payloadStub = $this->createStub(Event::class);
+    }
+
+    public function testCanCreateInstance(): void
+    {
+        $this->randomHelperStub->method('getRandomInt')->willReturn(123);
+        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+
+        $this->assertInstanceOf(
+            JobRunner::class,
+            new JobRunner(
+                $this->moduleConfigurationStub,
+                $this->sspConfigurationStub,
+                $this->loggerMock,
+                $this->helpersManagerStub,
+                $this->authenticationDataTrackerBuilderStub,
+                $this->jobsStoreBuilderStub,
+                $this->cacheMock,
+                $this->stateStub,
+                $this->rateLimiterMock
+            )
+        );
+    }
+
+    public function testPreRunValidationFailsForSameJobRunnerId(): void
+    {
+        $this->randomHelperStub->method('getRandomInt')->willReturn(123);
+        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+
+        $this->stateStub->method('getJobRunnerId')->willReturn(123);
+        $this->cacheMock->method('get')->willReturn($this->stateStub);
+
+        $this->cacheMock->expects($this->once())->method('delete');
+
+        $this->loggerMock->expects($this->once())->method('error')
+            ->with('Job runner ID in cached state same as new ID.');
+        $this->loggerMock->expects($this->atLeast(2))->method('warning')
+            ->withConsecutive(
+                [$this->stringContains('Pre-run state validation failed. Clearing cached state and continuing.')],
+                [$this->stringContains('Job runner called, however accounting mode is not')]
+            );
+
+        $jobRunner = new JobRunner(
+            $this->moduleConfigurationStub,
+            $this->sspConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManagerStub,
+            $this->authenticationDataTrackerBuilderStub,
+            $this->jobsStoreBuilderStub,
+            $this->cacheMock,
+            $this->stateStub,
+            $this->rateLimiterMock
+        );
+
+        $jobRunner->run();
+    }
+
+    public function testPreRunValidationFailsForStaleState(): void
+    {
+        $this->randomHelperStub->method('getRandomInt')->willReturn(123);
+        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+
+        $this->stateStub->method('getJobRunnerId')->willReturn(321);
+        $this->stateStub->method('isStale')->willReturn(true);
+        $this->cacheMock->method('get')->willReturn($this->stateStub);
+
+        $this->cacheMock->expects($this->once())->method('delete');
+
+        $this->loggerMock->expects($this->atLeast(3))->method('warning')
+            ->withConsecutive(
+                [$this->stringContains('Stale state encountered.')],
+                [$this->stringContains('Pre-run state validation failed. Clearing cached state and continuing.')],
+                [$this->stringContains('Job runner called, however accounting mode is not')]
+            );
+
+        $jobRunner = new JobRunner(
+            $this->moduleConfigurationStub,
+            $this->sspConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManagerStub,
+            $this->authenticationDataTrackerBuilderStub,
+            $this->jobsStoreBuilderStub,
+            $this->cacheMock,
+            $this->stateStub,
+            $this->rateLimiterMock
+        );
+
+        $jobRunner->run();
+    }
+
+    public function testPreRunValidationPassesWhenStateIsNull(): void
+    {
+        $this->randomHelperStub->method('getRandomInt')->willReturn(123);
+        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+
+        $this->cacheMock->method('get')->willReturn(null);
+
+        $this->cacheMock->expects($this->never())->method('delete');
+
+        $this->loggerMock->expects($this->atLeast(1))->method('warning')
+            ->withConsecutive(
+                [$this->stringContains('Job runner called, however accounting mode is not')]
+            );
+
+        $jobRunner = new JobRunner(
+            $this->moduleConfigurationStub,
+            $this->sspConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManagerStub,
+            $this->authenticationDataTrackerBuilderStub,
+            $this->jobsStoreBuilderStub,
+            $this->cacheMock,
+            $this->stateStub,
+            $this->rateLimiterMock
+        );
+
+        $jobRunner->run();
+    }
+
+    public function testValidateRunConditionsFailsIfAnotherJobRunnerIsActive(): void
+    {
+        $this->moduleConfigurationStub->method('getAccountingProcessingType')
+            ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
+
+        $this->randomHelperStub->method('getRandomInt')->willReturn(123);
+        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+
+        $this->stateStub->method('getJobRunnerId')->willReturn(321);
+        $this->stateStub->method('isStale')->willReturn(false);
+        $this->cacheMock->method('get')->willReturn($this->stateStub);
+
+        $this->cacheMock->expects($this->never())->method('delete');
+
+        $this->loggerMock->expects($this->once())->method('debug')
+            ->with($this->stringContains('Another job runner is active.'));
+        $this->loggerMock->expects($this->once())->method('info')
+            ->with($this->stringContains('Run conditions are not met, stopping.'));
+
+        $jobRunner = new JobRunner(
+            $this->moduleConfigurationStub,
+            $this->sspConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManagerStub,
+            $this->authenticationDataTrackerBuilderStub,
+            $this->jobsStoreBuilderStub,
+            $this->cacheMock,
+            $this->stateStub,
+            $this->rateLimiterMock
+        );
+
+        $jobRunner->run();
+    }
+
+    public function testAssumeTrueOnJobRunnerActivityIfThrown(): void
+    {
+        $this->moduleConfigurationStub->method('getAccountingProcessingType')
+            ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
+
+        $this->randomHelperStub->method('getRandomInt')->willReturn(123);
+        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+
+        $this->stateStub->method('getJobRunnerId')->willReturn(321);
+        $this->stateStub->method('isStale')->willReturn(false);
+        $this->cacheMock->method('get')->willReturnOnConsecutiveCalls(
+            $this->stateStub,
+            $this->throwException(new Exception('test'))
+        );
+
+        $this->cacheMock->expects($this->never())->method('delete');
+
+        $this->loggerMock->expects($this->once())->method('error')
+            ->with($this->stringContains('Error checking if another job runner is active.'));
+        $this->loggerMock->expects($this->once())->method('info')
+            ->with($this->stringContains('Run conditions are not met, stopping.'));
+
+        $jobRunner = new JobRunner(
+            $this->moduleConfigurationStub,
+            $this->sspConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManagerStub,
+            $this->authenticationDataTrackerBuilderStub,
+            $this->jobsStoreBuilderStub,
+            $this->cacheMock,
+            $this->stateStub,
+            $this->rateLimiterMock
+        );
+
+        $jobRunner->run();
+    }
+
+    public function testCanLogCacheClearingError(): void
+    {
+        $this->moduleConfigurationStub->method('getAccountingProcessingType')
+            ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
+
+        $this->randomHelperStub->method('getRandomInt')->willReturn(123);
+        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+
+        $this->stateStub->method('getJobRunnerId')->willReturn(321);
+        $this->stateStub->method('isStale')->willReturn(false);
+        $this->cacheMock->method('get')->willThrowException(new Exception('test'));
+        $this->cacheMock->method('delete')->willThrowException(new Exception('test'));
+
+        $this->expectException(Exception::class);
+
+        $this->loggerMock->expects($this->once())->method('error')
+            ->with($this->stringContains('Error clearing job runner cache.'));
+        $jobRunner = new JobRunner(
+            $this->moduleConfigurationStub,
+            $this->sspConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManagerStub,
+            $this->authenticationDataTrackerBuilderStub,
+            $this->jobsStoreBuilderStub,
+            $this->cacheMock,
+            $this->stateStub,
+            $this->rateLimiterMock
+        );
+
+        $jobRunner->run();
+    }
+
+    public function testValidateRunConditionsSuccessIfStaleStateEncountered(): void
+    {
+        $this->moduleConfigurationStub->method('getAccountingProcessingType')
+            ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
+
+        $this->randomHelperStub->method('getRandomInt')->willReturn(123);
+        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+
+        $this->stateStub->method('getJobRunnerId')->willReturn(321);
+        $this->stateStub->method('isStale')->willReturn(true);
+        $this->cacheMock->method('get')
+            ->willReturnOnConsecutiveCalls(
+                null,
+                $this->stateStub
+            );
+
+        $this->cacheMock->expects($this->once())->method('delete');
+
+        $this->loggerMock->expects($this->once())->method('warning')
+            ->with($this->stringContains('Assuming no job runner is active.'));
+        $this->loggerMock->expects($this->once())->method('debug')
+            ->with($this->stringContains('Run conditions validated.'));
+
+        $jobRunner = new JobRunner(
+            $this->moduleConfigurationStub,
+            $this->sspConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManagerStub,
+            $this->authenticationDataTrackerBuilderStub,
+            $this->jobsStoreBuilderStub,
+            $this->cacheMock,
+            $this->stateStub,
+            $this->rateLimiterMock
+        );
+
+        $jobRunner->run();
+    }
+
+    public function testShouldRunCheckFailsIfMaximumExecutionTimeIsReached(): void
+    {
+        $this->moduleConfigurationStub->method('getAccountingProcessingType')
+            ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
+
+        $this->moduleConfigurationStub->method('getJobRunnerMaximumExecutionTime')
+            ->willReturn(new \DateInterval('PT1S'));
+
+        $this->randomHelperStub->method('getRandomInt')->willReturn(123);
+        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+
+        $this->cacheMock->method('get')->willReturn(null);
+
+        $this->stateStub->method('getStartedAt')->willReturn(new \DateTimeImmutable('-2 seconds'));
+
+        $this->cacheMock->expects($this->once())->method('delete');
+
+        $this->loggerMock->expects($this->atLeast(2))->method('debug')
+            ->withConsecutive(
+                [$this->stringContains('Run conditions validated.')],
+                [$this->stringContains('Maximum job runner execution time reached.')]
+            );
+
+        $jobRunner = new JobRunner(
+            $this->moduleConfigurationStub,
+            $this->sspConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManagerStub,
+            $this->authenticationDataTrackerBuilderStub,
+            $this->jobsStoreBuilderStub,
+            $this->cacheMock,
+            $this->stateStub,
+            $this->rateLimiterMock
+        );
+
+        $jobRunner->run();
+    }
+
+    public function testCanUseIniSettingForMaximumExecutionTime(): void
+    {
+        $this->moduleConfigurationStub->method('getAccountingProcessingType')
+            ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
+
+        $this->moduleConfigurationStub->method('getJobRunnerMaximumExecutionTime')
+            ->willReturn(new \DateInterval('PT20S'));
+
+        $this->randomHelperStub->method('getRandomInt')->willReturn(123);
+        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->environmentHelperStub->method('isCli')->willReturn(false);
+        $this->helpersManagerStub->method('getEnvironmentHelper')->willReturn($this->environmentHelperStub);
+        $this->dateTimeHelperStub->method('convertDateIntervalToSeconds')->willReturn(20);
+        $this->helpersManagerStub->method('getDateTimeHelper')->willReturn($this->dateTimeHelperStub);
+
+        ini_set('max_execution_time', '10');
+
+        $this->cacheMock->method('get')->willReturn(null);
+
+        $this->stateStub->method('getStartedAt')->willReturn(new \DateTimeImmutable('-30 seconds'));
+
+        $this->cacheMock->expects($this->once())->method('delete');
+
+        $this->loggerMock->expects($this->atLeast(3))->method('debug')
+            ->withConsecutive(
+                [$this->stringContains('Using maximum execution time from INI setting since it is shorter.')],
+                [$this->stringContains('Run conditions validated.')],
+                [$this->stringContains('Maximum job runner execution time reached.')]
+            );
+
+        $jobRunner = new JobRunner(
+            $this->moduleConfigurationStub,
+            $this->sspConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManagerStub,
+            $this->authenticationDataTrackerBuilderStub,
+            $this->jobsStoreBuilderStub,
+            $this->cacheMock,
+            $this->stateStub,
+            $this->rateLimiterMock
+        );
+
+        $jobRunner->run();
+    }
+
+    public function testShouldRunCheckFailsIfMaximumNumberOfProcessedJobsIsReached(): void
+    {
+        $this->moduleConfigurationStub->method('getAccountingProcessingType')
+            ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
+
+        $this->randomHelperStub->method('getRandomInt')->willReturn(123);
+        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+
+        $this->cacheMock->method('get')->willReturn(null);
+
+        $this->stateStub->method('getTotalJobsProcessed')->willReturn(PHP_INT_MAX);
+
+        $this->cacheMock->expects($this->once())->method('delete');
+
+        $this->loggerMock->expects($this->atLeast(2))->method('debug')
+            ->withConsecutive(
+                [$this->stringContains('Run conditions validated.')],
+                [$this->stringContains('Maximum number of processed jobs reached.')]
+            );
+
+        $jobRunner = new JobRunner(
+            $this->moduleConfigurationStub,
+            $this->sspConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManagerStub,
+            $this->authenticationDataTrackerBuilderStub,
+            $this->jobsStoreBuilderStub,
+            $this->cacheMock,
+            $this->stateStub,
+            $this->rateLimiterMock
+        );
+
+        $jobRunner->run();
+    }
+
+    public function testValidateSelfStateFailsIfRunHasNotStartedButCachedStateExists(): void
+    {
+        $this->moduleConfigurationStub->method('getAccountingProcessingType')
+            ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
+
+        $this->randomHelperStub->method('getRandomInt')->willReturn(123);
+        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+
+        $this->cacheMock->method('get')->willReturnOnConsecutiveCalls(
+            null,
+            null,
+            null,
+            $this->stateStub
+        );
+
+        $this->stateStub->method('hasRunStarted')->willReturn(false);
+
+        $this->cacheMock->expects($this->once())->method('delete');
+
+        $this->loggerMock->expects($this->once())->method('warning')
+            ->with($this->stringContains('cached state has already been initialized.'));
+
+        $jobRunner = new JobRunner(
+            $this->moduleConfigurationStub,
+            $this->sspConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManagerStub,
+            $this->authenticationDataTrackerBuilderStub,
+            $this->jobsStoreBuilderStub,
+            $this->cacheMock,
+            $this->stateStub,
+            $this->rateLimiterMock
+        );
+
+        $jobRunner->run();
+    }
+
+    public function testValidateSelfStateFailsIfRunHasStartedButCachedStateDoesNotExist(): void
+    {
+        $this->moduleConfigurationStub->method('getAccountingProcessingType')
+            ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
+
+        $this->randomHelperStub->method('getRandomInt')->willReturn(123);
+        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+
+        $this->cacheMock->method('get')->willReturnOnConsecutiveCalls(
+            null,
+            null,
+            null,
+            null,
+        );
+
+        $this->stateStub->method('hasRunStarted')->willReturn(true);
+
+        $this->cacheMock->expects($this->once())->method('delete');
+
+        $this->loggerMock->expects($this->once())->method('warning')
+            ->with($this->stringContains('cached state has not been initialized.'));
+
+        $jobRunner = new JobRunner(
+            $this->moduleConfigurationStub,
+            $this->sspConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManagerStub,
+            $this->authenticationDataTrackerBuilderStub,
+            $this->jobsStoreBuilderStub,
+            $this->cacheMock,
+            $this->stateStub,
+            $this->rateLimiterMock
+        );
+
+        $jobRunner->run();
+    }
+
+    public function testValidateSelfStateFailsIfRunHasStartedButDifferentJobRunnerIdEncountered(): void
+    {
+        $this->moduleConfigurationStub->method('getAccountingProcessingType')
+            ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
+
+        $this->randomHelperStub->method('getRandomInt')->willReturn(123);
+        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+
+        $this->stateStub->method('getJobRunnerId')->willReturn(321);
+
+        $this->cacheMock->method('get')->willReturnOnConsecutiveCalls(
+            null,
+            null,
+            null,
+            $this->stateStub
+        );
+
+        $this->stateStub->method('hasRunStarted')->willReturn(true);
+
+        $this->cacheMock->expects($this->once())->method('delete');
+
+        $this->loggerMock->expects($this->once())->method('warning')
+            ->with($this->stringContains('Current job runner ID differs from the ID in the cached state.'));
+
+        $jobRunner = new JobRunner(
+            $this->moduleConfigurationStub,
+            $this->sspConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManagerStub,
+            $this->authenticationDataTrackerBuilderStub,
+            $this->jobsStoreBuilderStub,
+            $this->cacheMock,
+            $this->stateStub,
+            $this->rateLimiterMock
+        );
+
+        $jobRunner->run();
+    }
+
+    public function testValidateSelfStateFailsIfRunHasStartedButStaleCachedStateEncountered(): void
+    {
+        $this->moduleConfigurationStub->method('getAccountingProcessingType')
+            ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
+
+        $this->randomHelperStub->method('getRandomInt')->willReturn(123);
+        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+
+        $this->stateStub->method('getJobRunnerId')->willReturn(123);
+        $this->stateStub->method('isStale')->willReturn(true);
+
+        $this->cacheMock->method('get')->willReturnOnConsecutiveCalls(
+            null,
+            null,
+            null,
+            $this->stateStub
+        );
+
+        $this->stateStub->method('hasRunStarted')->willReturn(true);
+
+        $this->cacheMock->expects($this->once())->method('delete');
+
+        $this->loggerMock->expects($this->once())->method('warning')
+            ->with($this->stringContains('Job runner cached state is stale'));
+
+        $jobRunner = new JobRunner(
+            $this->moduleConfigurationStub,
+            $this->sspConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManagerStub,
+            $this->authenticationDataTrackerBuilderStub,
+            $this->jobsStoreBuilderStub,
+            $this->cacheMock,
+            $this->stateStub,
+            $this->rateLimiterMock
+        );
+
+        $jobRunner->run();
+    }
+
+    public function testValidateSelfStateFailsIfRunHasStartedButGracefulInterruptIsInitiated(): void
+    {
+        $this->moduleConfigurationStub->method('getAccountingProcessingType')
+            ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
+
+        $this->randomHelperStub->method('getRandomInt')->willReturn(123);
+        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+
+        $this->stateStub->method('getJobRunnerId')->willReturn(123);
+        $this->stateStub->method('isStale')->willReturn(false);
+        $this->stateStub->method('getIsGracefulInterruptInitiated')->willReturn(true);
+
+        $this->cacheMock->method('get')->willReturnOnConsecutiveCalls(
+            null,
+            null,
+            null,
+            $this->stateStub
+        );
+
+        $this->stateStub->method('hasRunStarted')->willReturn(true);
+
+        $this->cacheMock->expects($this->once())->method('delete');
+
+        $this->loggerMock->expects($this->once())->method('warning')
+            ->with($this->stringContains('Graceful job processing interrupt initiated'));
+
+        $jobRunner = new JobRunner(
+            $this->moduleConfigurationStub,
+            $this->sspConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManagerStub,
+            $this->authenticationDataTrackerBuilderStub,
+            $this->jobsStoreBuilderStub,
+            $this->cacheMock,
+            $this->stateStub,
+            $this->rateLimiterMock
+        );
+
+        $jobRunner->run();
+    }
+
+    public function testCanDoBackoffPauseIfNoJobsInCli(): void
+    {
+        $this->moduleConfigurationStub->method('getAccountingProcessingType')
+            ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
+
+        $this->randomHelperStub->method('getRandomInt')->willReturn(123);
+        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->environmentHelperStub->method('isCli')->willReturn(true);
+        $this->helpersManagerStub->method('getEnvironmentHelper')->willReturn($this->environmentHelperStub);
+
+        $this->stateStub->method('getJobRunnerId')->willReturn(123);
+        $this->stateStub->method('isStale')->willReturn(false);
+        $this->stateStub->method('getIsGracefulInterruptInitiated')
+            ->willReturnOnConsecutiveCalls(false, true);
+
+        $this->cacheMock->method('get')->willReturnOnConsecutiveCalls(
+            null,
+            null,
+            null,
+            $this->stateStub,
+            $this->stateStub
+        );
+
+        $this->stateStub->method('hasRunStarted')->willReturn(true);
+
+        $this->cacheMock->expects($this->once())->method('delete');
+
+        $this->loggerMock->expects($this->atLeast(2))->method('debug')
+            ->withConsecutive(
+                [$this->stringContains('Run conditions validated.')],
+                [$this->stringContains('Doing a backoff pause')]
+            );
+
+        $this->loggerMock->expects($this->once())->method('warning')
+            ->with($this->stringContains('Graceful job processing interrupt initiated'));
+
+        $jobRunner = new JobRunner(
+            $this->moduleConfigurationStub,
+            $this->sspConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManagerStub,
+            $this->authenticationDataTrackerBuilderStub,
+            $this->jobsStoreBuilderStub,
+            $this->cacheMock,
+            $this->stateStub,
+            $this->rateLimiterMock
+        );
+
+        $jobRunner->run();
+    }
+
+    public function testCanBreakImmediatelyIfNoJobsInWeb(): void
+    {
+        $this->moduleConfigurationStub->method('getAccountingProcessingType')
+            ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
+
+        $this->randomHelperStub->method('getRandomInt')->willReturn(123);
+        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->environmentHelperStub->method('isCli')->willReturn(false);
+        $this->helpersManagerStub->method('getEnvironmentHelper')->willReturn($this->environmentHelperStub);
+
+        $this->stateStub->method('getJobRunnerId')->willReturn(123);
+        $this->stateStub->method('isStale')->willReturn(false);
+        $this->stateStub->method('getIsGracefulInterruptInitiated')
+            ->willReturnOnConsecutiveCalls(false, true);
+
+        $this->cacheMock->method('get')->willReturnOnConsecutiveCalls(
+            null,
+            null,
+            null,
+            $this->stateStub,
+            $this->stateStub
+        );
+
+        $this->stateStub->method('hasRunStarted')->willReturn(true);
+
+        $this->cacheMock->expects($this->once())->method('delete');
+
+        $this->loggerMock->expects($this->once())->method('debug')
+            ->with($this->stringContains('Run conditions validated'));
+
+        $this->loggerMock->expects($this->never())->method('warning')
+            ->with($this->stringContains('Graceful job processing interrupt initiated'));
+
+        $jobRunner = new JobRunner(
+            $this->moduleConfigurationStub,
+            $this->sspConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManagerStub,
+            $this->authenticationDataTrackerBuilderStub,
+            $this->jobsStoreBuilderStub,
+            $this->cacheMock,
+            $this->stateStub,
+            $this->rateLimiterMock
+        );
+
+        $jobRunner->run();
+    }
+
+    public function testCanProcessJob(): void
+    {
+        $this->moduleConfigurationStub->method('getAccountingProcessingType')
+            ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
+        $this->moduleConfigurationStub->method('getDefaultDataTrackerAndProviderClass')
+            ->willReturn('mock');
+
+        $this->randomHelperStub->method('getRandomInt')->willReturn(123);
+        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->environmentHelperStub->method('isCli')->willReturn(false);
+        $this->helpersManagerStub->method('getEnvironmentHelper')->willReturn($this->environmentHelperStub);
+
+        $this->stateStub->method('getJobRunnerId')->willReturn(123);
+        $this->stateStub->method('isStale')->willReturn(false);
+        $this->stateStub->method('getIsGracefulInterruptInitiated')
+            ->willReturnOnConsecutiveCalls(false, true);
+
+        $this->cacheMock->method('get')->willReturnOnConsecutiveCalls(
+            null,
+            null,
+            null,
+            $this->stateStub,
+            $this->stateStub
+        );
+
+        $this->stateStub->method('hasRunStarted')->willReturn(true);
+
+        $this->rateLimiterMock->expects($this->once())->method('resetBackoffPause');
+
+        $this->authenticationDataTrackerMock->expects($this->once())
+            ->method('process');
+        $this->authenticationDataTrackerBuilderStub->method('build')
+            ->willReturn($this->authenticationDataTrackerMock);
+
+        $this->jobStub->method('getPayload')->willReturn($this->payloadStub);
+        $this->jobsStoreMock->method('dequeue')->willReturn($this->jobStub);
+        $this->jobsStoreBuilderStub->method('build')->willReturn($this->jobsStoreMock);
+
+        $this->cacheMock->expects($this->once())->method('delete');
+
+        $this->loggerMock->expects($this->atLeast(2))->method('debug')
+            ->withConsecutive(
+                [$this->stringContains('Run conditions validated.')],
+                [$this->stringContains('Successfully processed job with ID')]
+            );
+
+        $this->loggerMock->expects($this->once())->method('warning')
+            ->with($this->stringContains('Graceful job processing interrupt initiated'));
+
+        $jobRunner = new JobRunner(
+            $this->moduleConfigurationStub,
+            $this->sspConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManagerStub,
+            $this->authenticationDataTrackerBuilderStub,
+            $this->jobsStoreBuilderStub,
+            $this->cacheMock,
+            $this->stateStub,
+            $this->rateLimiterMock
+        );
+
+        $jobRunner->run();
+    }
+
+    public function testCanLogCacheUpdateError(): void
+    {
+        $this->moduleConfigurationStub->method('getAccountingProcessingType')
+            ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
+        $this->moduleConfigurationStub->method('getDefaultDataTrackerAndProviderClass')
+            ->willReturn('mock');
+
+        $this->randomHelperStub->method('getRandomInt')->willReturn(123);
+        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->environmentHelperStub->method('isCli')->willReturn(false);
+        $this->helpersManagerStub->method('getEnvironmentHelper')->willReturn($this->environmentHelperStub);
+
+        $this->stateStub->method('getJobRunnerId')->willReturn(123);
+        $this->stateStub->method('isStale')->willReturn(false);
+        $this->stateStub->method('getIsGracefulInterruptInitiated')
+            ->willReturnOnConsecutiveCalls(false, true);
+
+        $this->cacheMock->method('set')->willThrowException(new Exception('test'));
+
+        $this->cacheMock->method('get')->willReturnOnConsecutiveCalls(
+            null,
+            null,
+            null,
+            $this->stateStub,
+            $this->stateStub
+        );
+
+        $this->stateStub->method('hasRunStarted')->willReturn(true);
+
+        $this->jobStub->method('getPayload')->willReturn($this->payloadStub);
+        $this->jobsStoreMock->method('dequeue')->willReturn($this->jobStub);
+        $this->jobsStoreBuilderStub->method('build')->willReturn($this->jobsStoreMock);
+
+        $this->loggerMock->expects($this->atLeast(1))->method('debug')
+            ->withConsecutive(
+                [$this->stringContains('Run conditions validated.')],
+            );
+
+        $this->loggerMock->expects($this->once())->method('error')
+            ->with($this->stringContains('Error setting job runner state'));
+
+        $this->expectException(Exception::class);
+
+        $jobRunner = new JobRunner(
+            $this->moduleConfigurationStub,
+            $this->sspConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManagerStub,
+            $this->authenticationDataTrackerBuilderStub,
+            $this->jobsStoreBuilderStub,
+            $this->cacheMock,
+            $this->stateStub,
+            $this->rateLimiterMock
+        );
+
+        $jobRunner->run();
+    }
+
+    public function testCanPauseProcessingBasedOnConfiguration(): void
+    {
+        $this->moduleConfigurationStub->method('getAccountingProcessingType')
+            ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
+        $this->moduleConfigurationStub->method('getDefaultDataTrackerAndProviderClass')
+            ->willReturn('mock');
+        $this->moduleConfigurationStub->method('getJobRunnerShouldPauseAfterNumberOfJobsProcessed')
+            ->willReturn(0);
+
+        $this->randomHelperStub->method('getRandomInt')->willReturn(123);
+        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->environmentHelperStub->method('isCli')->willReturn(false);
+        $this->helpersManagerStub->method('getEnvironmentHelper')->willReturn($this->environmentHelperStub);
+
+        $this->stateStub->method('getJobRunnerId')->willReturn(123);
+        $this->stateStub->method('isStale')->willReturn(false);
+        $this->stateStub->method('getIsGracefulInterruptInitiated')
+            ->willReturnOnConsecutiveCalls(false, false, true);
+
+        $this->cacheMock->method('get')->willReturnOnConsecutiveCalls(
+            null,
+            null,
+            null,
+            $this->stateStub,
+            $this->stateStub,
+            $this->stateStub
+        );
+
+        $this->stateStub->method('hasRunStarted')->willReturn(true);
+
+        $this->rateLimiterMock->expects($this->exactly(2))->method('resetBackoffPause');
+        $this->rateLimiterMock->expects($this->once())->method('doPause');
+
+        $this->authenticationDataTrackerMock->expects($this->exactly(2))
+            ->method('process');
+        $this->authenticationDataTrackerBuilderStub->method('build')
+            ->willReturn($this->authenticationDataTrackerMock);
+
+        $this->jobStub->method('getPayload')->willReturn($this->payloadStub);
+        $this->jobsStoreMock->method('dequeue')->willReturn($this->jobStub);
+        $this->jobsStoreBuilderStub->method('build')->willReturn($this->jobsStoreMock);
+
+        $this->cacheMock->expects($this->once())->method('delete');
+
+        $this->loggerMock->expects($this->atLeast(3))->method('debug')
+            ->withConsecutive(
+                [$this->stringContains('Run conditions validated.')],
+                [$this->stringContains('Successfully processed job with ID')],
+                [$this->stringContains('Successfully processed job with ID')]
+            );
+
+        $this->loggerMock->expects($this->once())->method('warning')
+            ->with($this->stringContains('Graceful job processing interrupt initiated'));
+
+        $jobRunner = new JobRunner(
+            $this->moduleConfigurationStub,
+            $this->sspConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManagerStub,
+            $this->authenticationDataTrackerBuilderStub,
+            $this->jobsStoreBuilderStub,
+            $this->cacheMock,
+            $this->stateStub,
+            $this->rateLimiterMock
+        );
+
+        $jobRunner->run();
+    }
+
+    public function testCanMarkFailedJobOnError(): void
+    {
+        $this->moduleConfigurationStub->method('getAccountingProcessingType')
+            ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
+        $this->moduleConfigurationStub->method('getDefaultDataTrackerAndProviderClass')
+            ->willReturn('mock');
+
+        $this->randomHelperStub->method('getRandomInt')->willReturn(123);
+        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->environmentHelperStub->method('isCli')->willReturn(false);
+        $this->helpersManagerStub->method('getEnvironmentHelper')->willReturn($this->environmentHelperStub);
+
+        $this->stateStub->method('getJobRunnerId')->willReturn(123);
+        $this->stateStub->method('isStale')->willReturn(false);
+        $this->stateStub->method('getIsGracefulInterruptInitiated')
+            ->willReturnOnConsecutiveCalls(false, true);
+
+        $this->cacheMock->method('get')->willReturnOnConsecutiveCalls(
+            null,
+            null,
+            null,
+            $this->stateStub,
+            $this->stateStub
+        );
+
+        $this->stateStub->method('hasRunStarted')->willReturn(true);
+
+        $this->rateLimiterMock->expects($this->once())->method('resetBackoffPause');
+
+        $this->authenticationDataTrackerMock->expects($this->once())
+            ->method('process')
+            ->willThrowException(new Exception('test'));
+        $this->authenticationDataTrackerBuilderStub->method('build')
+            ->willReturn($this->authenticationDataTrackerMock);
+
+        $this->jobStub->method('getPayload')->willReturn($this->payloadStub);
+        $this->jobsStoreMock->method('dequeue')->willReturn($this->jobStub);
+        $this->jobsStoreMock->expects($this->once())->method('markFailedJob')->with($this->jobStub);
+        $this->jobsStoreBuilderStub->method('build')->willReturn($this->jobsStoreMock);
+
+        $this->cacheMock->expects($this->once())->method('delete');
+
+        $this->loggerMock->expects($this->once())->method('error')
+            ->with($this->stringContains('Error while processing jobs.'));
+
+        $this->loggerMock->expects($this->once())->method('warning')
+            ->with($this->stringContains('Graceful job processing interrupt initiated'));
+
+        $jobRunner = new JobRunner(
+            $this->moduleConfigurationStub,
+            $this->sspConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManagerStub,
+            $this->authenticationDataTrackerBuilderStub,
+            $this->jobsStoreBuilderStub,
+            $this->cacheMock,
+            $this->stateStub,
+            $this->rateLimiterMock
+        );
+
+        $jobRunner->run();
+    }
+
+    public function testThrowsOnAlreadyInitializedState(): void
+    {
+        $this->moduleConfigurationStub->method('getAccountingProcessingType')
+            ->willReturn(ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS);
+        $this->moduleConfigurationStub->method('getDefaultDataTrackerAndProviderClass')
+            ->willReturn('mock');
+
+        $this->randomHelperStub->method('getRandomInt')->willReturn(123);
+        $this->helpersManagerStub->method('getRandomHelper')->willReturn($this->randomHelperStub);
+        $this->environmentHelperStub->method('isCli')->willReturn(false);
+        $this->helpersManagerStub->method('getEnvironmentHelper')->willReturn($this->environmentHelperStub);
+
+        $this->stateStub->method('getJobRunnerId')->willReturn(123);
+        $this->stateStub->method('isStale')->willReturn(false);
+        $this->stateStub->method('getIsGracefulInterruptInitiated')
+            ->willReturnOnConsecutiveCalls(false, true);
+
+        $this->cacheMock->method('get')->willReturnOnConsecutiveCalls(
+            null,
+            null,
+            $this->stateStub
+        );
+
+        $this->stateStub->method('hasRunStarted')->willReturn(true);
+
+        $this->loggerMock->expects($this->once())->method('error')
+            ->with($this->stringContains('Job runner state already initialized'));
+        $this->expectException(Exception::class);
+
+        $jobRunner = new JobRunner(
+            $this->moduleConfigurationStub,
+            $this->sspConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManagerStub,
+            $this->authenticationDataTrackerBuilderStub,
+            $this->jobsStoreBuilderStub,
+            $this->cacheMock,
+            $this->stateStub,
+            $this->rateLimiterMock
+        );
+
+        $jobRunner->run();
+    }
+}
diff --git a/tests/src/Services/LoggerServiceTest.php b/tests/src/Services/LoggerServiceTest.php
new file mode 100644
index 0000000..241dfeb
--- /dev/null
+++ b/tests/src/Services/LoggerServiceTest.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Services;
+
+use SimpleSAML\Module\accounting\Services\Logger;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Services\Logger
+ */
+class LoggerServiceTest extends TestCase
+{
+    public function testCanCallAllMethods(): void
+    {
+        $loggerService = new Logger();
+
+        $loggerService->stats('test');
+        $loggerService->debug('test');
+        $loggerService->info('test');
+        $loggerService->notice('test');
+        $loggerService->warning('test');
+        $loggerService->error('test');
+        $loggerService->alert('test');
+        $loggerService->critical('test');
+        $loggerService->emergency('test');
+
+        $loggerService->emergency('test', ['sample' => 'context']);
+
+        $this->assertTrue(true); // Nothing to evaluate
+    }
+}
diff --git a/tests/src/Stores/Bases/AbstractStoreTest.php b/tests/src/Stores/Bases/AbstractStoreTest.php
new file mode 100644
index 0000000..5580ba7
--- /dev/null
+++ b/tests/src/Stores/Bases/AbstractStoreTest.php
@@ -0,0 +1,63 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Bases;
+
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Stores\Bases\AbstractStore;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Bases\AbstractStore
+ */
+class AbstractStoreTest extends TestCase
+{
+    /**
+     * @var AbstractStore
+     */
+    protected $abstractStore;
+    /**
+     * @var \PHPUnit\Framework\MockObject\Stub|ModuleConfiguration
+     */
+    protected $moduleConfigurationStub;
+    /**
+     * @var \PHPUnit\Framework\MockObject\Stub|LoggerInterface
+     */
+    protected $loggerStub;
+
+    protected function setUp(): void
+    {
+        $this->moduleConfigurationStub = $this->createStub(ModuleConfiguration::class);
+        $this->loggerStub = $this->createStub(LoggerInterface::class);
+
+        $this->abstractStore = new class (
+            $this->moduleConfigurationStub,
+            $this->loggerStub
+        ) extends AbstractStore {
+            public static function build(
+                ModuleConfiguration $moduleConfiguration,
+                LoggerInterface $logger,
+                string $connectionKey = null
+            ): AbstractStore {
+                return new self($moduleConfiguration, $logger, $connectionKey);
+            }
+            public function needsSetup(): bool
+            {
+                return false;
+            }
+            public function runSetup(): void
+            {
+            }
+        };
+    }
+
+    public function testCanBuildInstance(): void
+    {
+        $this->assertInstanceOf(AbstractStore::class, $this->abstractStore);
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $this->assertInstanceOf(
+            AbstractStore::class,
+            $this->abstractStore::build($this->moduleConfigurationStub, $this->loggerStub)
+        );
+    }
+}
diff --git a/tests/src/Stores/Bases/DoctrineDbal/AbstractRawEntityTest.php b/tests/src/Stores/Bases/DoctrineDbal/AbstractRawEntityTest.php
new file mode 100644
index 0000000..9f8ae4c
--- /dev/null
+++ b/tests/src/Stores/Bases/DoctrineDbal/AbstractRawEntityTest.php
@@ -0,0 +1,74 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Bases\DoctrineDbal;
+
+use Doctrine\DBAL\Platforms\AbstractPlatform;
+use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+use SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractRawEntity;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Test\Module\accounting\Constants\DateTime;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractRawEntity
+ */
+class AbstractRawEntityTest extends TestCase
+{
+    /**
+     * @var AbstractPlatform|AbstractPlatform&\PHPUnit\Framework\MockObject\Stub|\PHPUnit\Framework\MockObject\Stub
+     */
+    protected $abstractPlatformStub;
+    /**
+     * @var string[]
+     */
+    protected array $rawRow;
+
+    protected function setUp(): void
+    {
+        $this->abstractPlatformStub = $this->createStub(AbstractPlatform::class);
+        $this->abstractPlatformStub->method('getDateTimeFormatString')
+            ->willReturn(DateTime::DEFAULT_FORMAT);
+        $this->rawRow = ['sample' => 'test'];
+    }
+
+    public function testCanCreateInstance(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $rawEntityInstance = new class ($this->rawRow, $this->abstractPlatformStub) extends AbstractRawEntity {
+            protected function validate(
+                array $rawRow
+            ): void {
+            }
+        };
+        $this->assertInstanceOf(AbstractRawEntity::class, $rawEntityInstance);
+    }
+
+    public function testCanResolveDateTimeImmutable(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $rawEntityInstance = new class ($this->rawRow, $this->abstractPlatformStub) extends AbstractRawEntity {
+            protected function validate(
+                array $rawRow
+            ): void {
+                $this->resolveDateTimeImmutable('2022-09-21 14:49:20');
+            }
+        };
+
+        $this->assertInstanceOf(AbstractRawEntity::class, $rawEntityInstance);
+    }
+
+    public function testThrowsForInvalidDateTime(): void
+    {
+        $this->expectException(UnexpectedValueException::class);
+
+        /** @psalm-suppress InvalidArgument */
+        new class ($this->rawRow, $this->abstractPlatformStub) extends AbstractRawEntity {
+            protected function validate(
+                array $rawRow
+            ): void {
+                $this->resolveDateTimeImmutable('invalid');
+            }
+        };
+    }
+}
diff --git a/tests/src/Stores/Builders/DataStoreBuilderTest.php b/tests/src/Stores/Builders/DataStoreBuilderTest.php
new file mode 100644
index 0000000..c007b88
--- /dev/null
+++ b/tests/src/Stores/Builders/DataStoreBuilderTest.php
@@ -0,0 +1,63 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Builders;
+
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Module\accounting\Exceptions\StoreException;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+use SimpleSAML\Module\accounting\Stores\Builders\DataStoreBuilder;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store;
+use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Builders\DataStoreBuilder
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store
+ * @uses \SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfigurationHelper
+ * @uses \SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractStore
+ * @uses \SimpleSAML\Module\accounting\Stores\Builders\Bases\AbstractStoreBuilder
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Factory
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Repository
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\Bases\AbstractMigrator
+ * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
+ * @uses \SimpleSAML\Module\accounting\Stores\Bases\AbstractStore
+ */
+class DataStoreBuilderTest extends TestCase
+{
+    protected \PHPUnit\Framework\MockObject\Stub $moduleConfigurationStub;
+    protected \PHPUnit\Framework\MockObject\Stub $loggerStub;
+    protected DataStoreBuilder $dataStoreBuilder;
+    protected HelpersManager $helpersManager;
+
+    protected function setUp(): void
+    {
+        $this->moduleConfigurationStub = $this->createStub(ModuleConfiguration::class);
+        $this->moduleConfigurationStub->method('getConnectionParameters')
+            ->willReturn(ConnectionParameters::DBAL_SQLITE_MEMORY);
+
+        $this->loggerStub = $this->createStub(LoggerInterface::class);
+
+        $this->helpersManager = new HelpersManager();
+
+        /** @psalm-suppress InvalidArgument */
+        $this->dataStoreBuilder = new DataStoreBuilder(
+            $this->moduleConfigurationStub,
+            $this->loggerStub,
+            $this->helpersManager
+        );
+    }
+
+    public function testCanBuildDataStore(): void
+    {
+        $this->assertInstanceOf(Store::class, $this->dataStoreBuilder->build(Store::class));
+    }
+
+    public function testThrowsForInvalidDataStoreClass(): void
+    {
+        $this->expectException(StoreException::class);
+        $this->dataStoreBuilder->build(ModuleConfiguration::class);
+    }
+}
diff --git a/tests/src/Stores/Builders/JobsStoreBuilderTest.php b/tests/src/Stores/Builders/JobsStoreBuilderTest.php
new file mode 100644
index 0000000..02166c8
--- /dev/null
+++ b/tests/src/Stores/Builders/JobsStoreBuilderTest.php
@@ -0,0 +1,138 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Builders;
+
+use PHPUnit\Framework\TestCase;
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Module\accounting\Exceptions\StoreException;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+use SimpleSAML\Module\accounting\Stores\Builders\Bases\AbstractStoreBuilder;
+use SimpleSAML\Module\accounting\Stores\Builders\JobsStoreBuilder;
+use SimpleSAML\Module\accounting\Stores\Interfaces\StoreInterface;
+use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store;
+use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Builders\Bases\AbstractStoreBuilder
+ * @covers \SimpleSAML\Module\accounting\Stores\Builders\JobsStoreBuilder
+ * @uses   \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Factory
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator
+ * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Repository
+ * @uses \SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractStore
+ * @uses \SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfigurationHelper
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\Bases\AbstractMigrator
+ * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
+ * @uses \SimpleSAML\Module\accounting\Stores\Bases\AbstractStore
+ */
+class JobsStoreBuilderTest extends TestCase
+{
+    protected \PHPUnit\Framework\MockObject\Stub $moduleConfigurationStub;
+    protected \PHPUnit\Framework\MockObject\Stub $loggerStub;
+    protected JobsStoreBuilder $jobsStoreBuilder;
+    protected HelpersManager $helpersManager;
+
+    protected function setUp(): void
+    {
+        $this->moduleConfigurationStub = $this->createStub(ModuleConfiguration::class);
+        $this->moduleConfigurationStub->method('getConnectionParameters')
+            ->willReturn(ConnectionParameters::DBAL_SQLITE_MEMORY);
+        $this->moduleConfigurationStub->method('getJobsStoreClass')->willReturn(Store::class);
+
+        $this->loggerStub = $this->createStub(LoggerInterface::class);
+
+        $this->helpersManager = new HelpersManager();
+
+        /** @psalm-suppress InvalidArgument */
+        $this->jobsStoreBuilder = new JobsStoreBuilder(
+            $this->moduleConfigurationStub,
+            $this->loggerStub,
+            $this->helpersManager
+        );
+    }
+
+    public function testCanBuildJobsStore(): void
+    {
+        $this->assertInstanceOf(Store::class, $this->jobsStoreBuilder->build(Store::class));
+    }
+
+    public function testThrowsForInvalidStoreClass(): void
+    {
+        $moduleConfigurationStub = $this->createStub(ModuleConfiguration::class);
+        $moduleConfigurationStub->method('getConnectionParameters')
+            ->willReturn(ConnectionParameters::DBAL_SQLITE_MEMORY);
+
+        $invalidStore = new class {
+        };
+
+        /** @psalm-suppress InvalidArgument */
+        $storeBuilder = new class (
+            $moduleConfigurationStub,
+            $this->loggerStub,
+            $this->helpersManager
+        ) extends AbstractStoreBuilder {
+            public function build(
+                string $class,
+                string $connectionKey = null,
+                string $connectionType = ModuleConfiguration\ConnectionType::MASTER
+            ): StoreInterface {
+                return $this->buildGeneric($class, [$connectionKey, $connectionType]);
+            }
+        };
+
+        $this->expectException(StoreException::class);
+
+        /** @psalm-suppress InvalidArgument */
+        $storeBuilder->build(get_class($invalidStore));
+    }
+
+    public function testThrowsForInvalidJobsStoreClass(): void
+    {
+        $moduleConfigurationStub = $this->createStub(ModuleConfiguration::class);
+        $moduleConfigurationStub->method('getConnectionParameters')
+            ->willReturn(ConnectionParameters::DBAL_SQLITE_MEMORY);
+
+        $this->expectException(StoreException::class);
+
+        /** @psalm-suppress InvalidArgument */
+        (new JobsStoreBuilder($moduleConfigurationStub, $this->loggerStub, $this->helpersManager))
+            ->build('invalid');
+    }
+
+    public function testJobsStoreBuilderOnlyReturnsJobsStores(): void
+    {
+        $sampleStore = new class implements StoreInterface {
+            public function needsSetup(): bool
+            {
+                return false;
+            }
+
+            public function runSetup(): void
+            {
+            }
+
+            public static function build(
+                ModuleConfiguration $moduleConfiguration,
+                LoggerInterface $logger,
+                string $connectionKey = null
+            ): StoreInterface {
+                return new self();
+            }
+        };
+
+        $moduleConfigurationStub = $this->createStub(ModuleConfiguration::class);
+        $moduleConfigurationStub->method('getConnectionParameters')
+            ->willReturn(ConnectionParameters::DBAL_SQLITE_MEMORY);
+        $moduleConfigurationStub->method('getJobsStoreClass')->willReturn(get_class($sampleStore));
+
+        $this->expectException(StoreException::class);
+
+        /** @psalm-suppress InvalidArgument */
+        (new JobsStoreBuilder($moduleConfigurationStub, $this->loggerStub, $this->helpersManager))
+            ->build(get_class($sampleStore));
+    }
+}
diff --git a/tests/src/Stores/Connections/Bases/AbstractMigratorTest.php b/tests/src/Stores/Connections/Bases/AbstractMigratorTest.php
new file mode 100644
index 0000000..0fb3fda
--- /dev/null
+++ b/tests/src/Stores/Connections/Bases/AbstractMigratorTest.php
@@ -0,0 +1,185 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Connections\Bases;
+
+use Doctrine\DBAL\Schema\AbstractSchemaManager;
+use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Services\Logger;
+use SimpleSAML\Module\accounting\Stores\Connections\Bases\AbstractMigrator;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator;
+use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store;
+use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Connections\Bases\AbstractMigrator
+ * @uses \SimpleSAML\Module\accounting\Helpers\FilesystemHelper
+ * @uses \SimpleSAML\Module\accounting\ModuleConfiguration
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator
+ * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Version20220601000000CreateJobTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Version20220601000100CreateJobFailedTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration
+ * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Bases\AbstractCreateJobsTable
+ * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
+ */
+class AbstractMigratorTest extends TestCase
+{
+    protected Connection $connection;
+    protected AbstractSchemaManager $schemaManager;
+    protected string $tableName;
+
+    /**
+     * @var \PHPUnit\Framework\MockObject\MockObject
+     */
+    protected $loggerServiceMock;
+    protected ModuleConfiguration $moduleConfiguration;
+
+    protected function setUp(): void
+    {
+        parent::setUp();
+        $this->connection = new Connection(ConnectionParameters::DBAL_SQLITE_MEMORY);
+
+        $this->schemaManager = $this->connection->dbal()->createSchemaManager();
+        $this->tableName = $this->connection->preparePrefixedTableName(Migrator::TABLE_NAME);
+
+        $this->loggerServiceMock = $this->createMock(Logger::class);
+
+        // Configuration directory is set by phpunit using php ENV setting feature (check phpunit.xml).
+        $this->moduleConfiguration = new ModuleConfiguration('module_accounting.php');
+    }
+
+    public function testCanGatherMigrationClassesFromDirectory(): void
+    {
+        /** @psalm-suppress InvalidArgument Using mock instead of Logger instance */
+        $migrator = new Migrator($this->connection, $this->loggerServiceMock);
+
+        $directory = $this->getSampleMigrationsDirectory();
+
+        $namespace = $this->getSampleNameSpace();
+
+        $migrationClasses = $migrator->gatherMigrationClassesFromDirectory($directory, $namespace);
+
+        $this->assertTrue(in_array($namespace . '\Version20220601000000CreateJobTable', $migrationClasses));
+    }
+
+    public function testCanRunMigrationClasses(): void
+    {
+        /** @psalm-suppress InvalidArgument Using mock instead of Logger instance */
+        $migrator = new Migrator($this->connection, $this->loggerServiceMock);
+
+        $migrator->runSetup();
+
+        $directory = $this->getSampleMigrationsDirectory();
+
+        $namespace = $this->getSampleNameSpace();
+
+        $migrationClasses = $migrator->gatherMigrationClassesFromDirectory($directory, $namespace);
+
+        $jobsTableName = $this->connection->preparePrefixedTableName(Store\TableConstants::TABLE_NAME_JOB);
+
+        $this->assertFalse($this->schemaManager->tablesExist($jobsTableName));
+
+        $migrator->runMigrationClasses($migrationClasses);
+
+        $this->assertTrue($this->schemaManager->tablesExist($jobsTableName));
+    }
+
+    public function testCanGatherOnlyMigrationClasses(): void
+    {
+        /** @psalm-suppress InvalidArgument Using mock instead of Logger instance */
+        $migrator = new Migrator($this->connection, $this->loggerServiceMock);
+
+        $directory = __DIR__;
+        $namespace = __NAMESPACE__;
+
+        $this->assertEmpty($migrator->gatherMigrationClassesFromDirectory($directory, $namespace));
+    }
+
+    public function testMigrationExceptionHaltsExecution(): void
+    {
+        $migration = new class ($this->connection) extends AbstractMigration
+        {
+            public function run(): void
+            {
+                throw new \Exception('Something went wrong.');
+            }
+
+            public function revert(): void
+            {
+            }
+        };
+
+        /** @psalm-suppress InvalidArgument Using mock instead of Logger instance */
+        $migrator = new Migrator($this->connection, $this->loggerServiceMock);
+
+        $this->expectException(MigrationException::class);
+
+        $migrator->runMigrationClasses([get_class($migration)]);
+    }
+
+    public function testCanGetNonImplementedMigrationClasses(): void
+    {
+        /** @psalm-suppress InvalidArgument Using mock instead of Logger instance */
+        $migrator = new Migrator($this->connection, $this->loggerServiceMock);
+
+        $migrator->runSetup();
+
+        $nonImplementedMigrationClasses = $migrator->getNonImplementedMigrationClasses(
+            $this->getSampleMigrationsDirectory(),
+            $this->getSampleNameSpace()
+        );
+
+        $this->assertTrue(in_array(
+            Store\Migrations\Version20220601000000CreateJobTable::class,
+            $nonImplementedMigrationClasses
+        ));
+    }
+
+    public function testCanFindOutIfNonImplementedMigrationClassesExist(): void
+    {
+        /** @psalm-suppress InvalidArgument Using mock instead of Logger instance */
+        $migrator = new Migrator($this->connection, $this->loggerServiceMock);
+
+        $migrator->runSetup();
+
+        $this->assertTrue($migrator->hasNonImplementedMigrationClasses(
+            $this->getSampleMigrationsDirectory(),
+            $this->getSampleNameSpace()
+        ));
+    }
+
+    public function testCanRunNonImplementedMigrationClasses(): void
+    {
+        /** @psalm-suppress InvalidArgument Using mock instead of Logger instance */
+        $migrator = new Migrator($this->connection, $this->loggerServiceMock);
+
+        $migrator->runSetup();
+
+        $directory = $this->getSampleMigrationsDirectory();
+        $namespace = $this->getSampleNameSpace();
+
+        $this->assertTrue($migrator->hasNonImplementedMigrationClasses($directory, $namespace));
+
+        $migrator->runNonImplementedMigrationClasses($directory, $namespace);
+
+        $this->assertFalse($migrator->hasNonImplementedMigrationClasses($directory, $namespace));
+    }
+
+    protected function getSampleMigrationsDirectory(): string
+    {
+        return $this->moduleConfiguration->getModuleSourceDirectory() . DIRECTORY_SEPARATOR .
+            'Stores' . DIRECTORY_SEPARATOR . 'Jobs' . DIRECTORY_SEPARATOR . 'DoctrineDbal' . DIRECTORY_SEPARATOR .
+            'Store' . DIRECTORY_SEPARATOR . AbstractMigrator::DEFAULT_MIGRATIONS_DIRECTORY_NAME;
+    }
+
+    protected function getSampleNameSpace(): string
+    {
+        return Store::class . '\\' . AbstractMigrator::DEFAULT_MIGRATIONS_DIRECTORY_NAME;
+    }
+}
diff --git a/tests/src/Stores/Connections/DoctrineDbal/Bases/AbstractMigrationTest.php b/tests/src/Stores/Connections/DoctrineDbal/Bases/AbstractMigrationTest.php
new file mode 100644
index 0000000..68db88b
--- /dev/null
+++ b/tests/src/Stores/Connections/DoctrineDbal/Bases/AbstractMigrationTest.php
@@ -0,0 +1,115 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Connections\DoctrineDbal\Bases;
+
+use SimpleSAML\Module\accounting\Exceptions\StoreException;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection;
+use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Version20220601000000CreateJobTable;
+use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration
+ * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Version20220601000000CreateJobTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection
+ */
+class AbstractMigrationTest extends TestCase
+{
+    protected Connection $connection;
+
+    protected function setUp(): void
+    {
+        parent::setUp();
+        $this->connection = new Connection(ConnectionParameters::DBAL_SQLITE_MEMORY);
+    }
+
+    public function testCanInstantiateMigrationClass(): void
+    {
+        $this->assertInstanceOf(
+            AbstractMigration::class,
+            new Version20220601000000CreateJobTable($this->connection)
+        );
+    }
+
+    public function testThrowsStoreException(): void
+    {
+        $dbalStub = $this->createStub(\Doctrine\DBAL\Connection::class);
+        $dbalStub->method('createSchemaManager')
+            ->willThrowException(new \Doctrine\DBAL\Exception('test'));
+        $connectionStub = $this->createStub(Connection::class);
+        $connectionStub->method('dbal')->willReturn($dbalStub);
+
+        $this->expectException(StoreException::class);
+
+        (new Version20220601000000CreateJobTable($connectionStub));
+    }
+
+    public function testCanThrowGenericMigrationExceptionOnRun(): void
+    {
+        $migration = new class ($this->connection) extends AbstractMigration {
+            public function run(): void
+            {
+                throw $this->prepareGenericMigrationException('test', new \Exception('test'));
+            }
+
+            public function revert(): void
+            {
+            }
+        };
+
+        $this->expectException(StoreException\MigrationException::class);
+
+        $migration->run();
+    }
+
+    public function testCanUseTableNamePrefix(): void
+    {
+        $connectionStub = $this->createStub(Connection::class);
+        $connectionStub->method('dbal')->willReturn($this->connection->dbal());
+        $connectionStub->method('preparePrefixedTableName')->willReturn('prefix-connection');
+
+        $migration = new class ($connectionStub) extends AbstractMigration {
+            public function run(): void
+            {
+                throw new \Exception($this->preparePrefixedTableName('table-name'));
+            }
+            public function revert(): void
+            {
+            }
+            protected function getLocalTablePrefix(): string
+            {
+                return 'prefix-local';
+            }
+        };
+
+        try {
+            $migration->run();
+        } catch (\Exception $exception) {
+            $this->assertStringContainsString('prefix-connection', $exception->getMessage());
+        }
+    }
+
+    public function testCanUseLocalTableNamePrefix(): void
+    {
+        $connectionStub = $this->createStub(Connection::class);
+        $connectionStub->method('dbal')->willReturn($this->connection->dbal());
+        $connectionStub->method('preparePrefixedTableName')->willReturn('prefix-connection');
+
+        $migration = new class ($connectionStub) extends AbstractMigration {
+            public function run(): void
+            {
+                throw new \Exception($this->getLocalTablePrefix());
+            }
+            public function revert(): void
+            {
+            }
+        };
+
+        try {
+            $migration->run();
+        } catch (\Exception $exception) {
+            $this->assertEmpty($exception->getMessage());
+        }
+    }
+}
diff --git a/tests/src/Stores/Connections/DoctrineDbal/ConnectionTest.php b/tests/src/Stores/Connections/DoctrineDbal/ConnectionTest.php
new file mode 100644
index 0000000..cbc1f86
--- /dev/null
+++ b/tests/src/Stores/Connections/DoctrineDbal/ConnectionTest.php
@@ -0,0 +1,55 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Connections\DoctrineDbal;
+
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Exceptions\InvalidConfigurationException;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection
+ */
+class ConnectionTest extends TestCase
+{
+    protected array $parameters = [
+        'driver' => 'pdo_sqlite',
+        'memory' => true,
+    ];
+
+    public function testCanInstantiateDbalConnection(): void
+    {
+        $connection = new Connection($this->parameters);
+
+        $this->assertInstanceOf(\Doctrine\DBAL\Connection::class, $connection->dbal());
+    }
+
+    public function testInvalidConnectionParametersThrow(): void
+    {
+        $this->expectException(InvalidConfigurationException::class);
+        (new Connection(['invalid' => 'parameter']));
+    }
+
+    public function testCanSetTablePrefix(): void
+    {
+        $prefix = 'test_';
+        $parameters = $this->parameters;
+        $parameters['table_prefix'] = $prefix;
+
+        $connection = new Connection($parameters);
+
+        $this->assertEquals($prefix, $connection->getTablePrefix());
+
+        $this->assertSame('test_test', $connection->preparePrefixedTableName('test'));
+    }
+
+    public function testTablePrefixParameterThrowsIfNotString(): void
+    {
+        $this->expectException(InvalidConfigurationException::class);
+
+        $parameters = $this->parameters;
+        $parameters['table_prefix'] = new class () {
+        };
+
+        (new Connection($parameters));
+    }
+}
diff --git a/tests/src/Stores/Connections/DoctrineDbal/FactoryTest.php b/tests/src/Stores/Connections/DoctrineDbal/FactoryTest.php
new file mode 100644
index 0000000..07dab2d
--- /dev/null
+++ b/tests/src/Stores/Connections/DoctrineDbal/FactoryTest.php
@@ -0,0 +1,54 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Connections\DoctrineDbal;
+
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Services\Logger;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Factory;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator;
+use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Factory
+ * @uses \SimpleSAML\Module\accounting\ModuleConfiguration
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\Bases\AbstractMigrator
+ * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
+ */
+class FactoryTest extends TestCase
+{
+    protected ModuleConfiguration $moduleConfiguration;
+
+    /**
+     * @var \PHPUnit\Framework\MockObject\MockObject
+     */
+    protected $loggerServiceMock;
+
+    protected function setUp(): void
+    {
+        // Configuration directory is set by phpunit using php ENV setting feature (check phpunit.xml).
+        $this->moduleConfiguration = new ModuleConfiguration('module_accounting.php');
+        $this->loggerServiceMock = $this->createMock(Logger::class);
+    }
+
+    public function testCanBuildConnection(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $factory = new Factory($this->moduleConfiguration, $this->loggerServiceMock);
+
+        $this->assertInstanceOf(Connection::class, $factory->buildConnection('doctrine_dbal_pdo_sqlite'));
+    }
+
+    public function testCanBuildMigrator(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $factory = new Factory($this->moduleConfiguration, $this->loggerServiceMock);
+
+        $connection = new Connection(ConnectionParameters::DBAL_SQLITE_MEMORY);
+
+        $this->assertInstanceOf(Migrator::class, $factory->buildMigrator($connection));
+    }
+}
diff --git a/tests/src/Stores/Connections/DoctrineDbal/MigratorTest.php b/tests/src/Stores/Connections/DoctrineDbal/MigratorTest.php
new file mode 100644
index 0000000..907e83c
--- /dev/null
+++ b/tests/src/Stores/Connections/DoctrineDbal/MigratorTest.php
@@ -0,0 +1,238 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Connections\DoctrineDbal;
+
+use Doctrine\DBAL\Query\QueryBuilder;
+use PHPUnit\Framework\TestCase;
+use Doctrine\DBAL\Schema\AbstractSchemaManager;
+use SimpleSAML\Module\accounting\Exceptions\InvalidValueException;
+use SimpleSAML\Module\accounting\Exceptions\StoreException;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Services\Logger;
+use SimpleSAML\Module\accounting\Stores\Connections\Bases\AbstractMigrator;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection;
+use SimpleSAML\Module\accounting\Stores\Interfaces\MigrationInterface;
+use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store;
+use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
+
+use function PHPUnit\Framework\assertFalse;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator
+ * @covers \SimpleSAML\Module\accounting\Stores\Connections\Bases\AbstractMigrator
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration
+ * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Version20220601000000CreateJobTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Version20220601000100CreateJobFailedTable
+ * @uses \SimpleSAML\Module\accounting\ModuleConfiguration
+ * @uses \SimpleSAML\Module\accounting\Helpers\FilesystemHelper
+ * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Bases\AbstractCreateJobsTable
+ * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
+ */
+class MigratorTest extends TestCase
+{
+    protected Connection $connection;
+    protected AbstractSchemaManager $schemaManager;
+    protected string $tableName;
+
+    /**
+     * @var \PHPUnit\Framework\MockObject\MockObject
+     */
+    protected $loggerServiceMock;
+    protected ModuleConfiguration $moduleConfiguration;
+
+    protected function setUp(): void
+    {
+        parent::setUp();
+        $this->connection = new Connection(ConnectionParameters::DBAL_SQLITE_MEMORY);
+
+        $this->schemaManager = $this->connection->dbal()->createSchemaManager();
+        $this->tableName = $this->connection->preparePrefixedTableName(Migrator::TABLE_NAME);
+
+        $this->loggerServiceMock = $this->createMock(Logger::class);
+
+        // Configuration directory is set by phpunit using php ENV setting feature (check phpunit.xml).
+        $this->moduleConfiguration = new ModuleConfiguration('module_accounting.php');
+    }
+
+    public function testCanCreateMigrationsTable(): void
+    {
+        $this->assertFalse($this->schemaManager->tablesExist([$this->tableName]));
+
+        /** @psalm-suppress InvalidArgument Using mock instead of Logger instance */
+        $migrator = new Migrator($this->connection, $this->loggerServiceMock);
+
+        $this->assertTrue($migrator->needsSetup());
+
+        $migrator->runSetup();
+
+        $this->assertFalse($migrator->needsSetup());
+        $this->assertTrue($this->schemaManager->tablesExist([$this->tableName]));
+    }
+
+    public function testRunningMigratorSetupMultipleTimesLogsWarning(): void
+    {
+        $this->loggerServiceMock
+            ->expects($this->once())
+            ->method('warning')
+            ->with($this->stringContains('setup is not needed'));
+
+        /** @psalm-suppress InvalidArgument Using mock instead of Logger instance */
+        $migrator = new Migrator($this->connection, $this->loggerServiceMock);
+
+        $this->assertTrue($migrator->needsSetup());
+
+        $migrator->runSetup();
+        $migrator->runSetup();
+    }
+
+    public function testCanRunMigrationClasses(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $migrator = new Migrator($this->connection, $this->loggerServiceMock);
+
+        $migrator->runSetup();
+
+        $tableNameJobs = $this->connection->preparePrefixedTableName(Store\TableConstants::TABLE_NAME_JOB);
+        $this > assertFalse($this->schemaManager->tablesExist($tableNameJobs));
+
+        $migrator->runMigrationClasses([Store\Migrations\Version20220601000000CreateJobTable::class]);
+
+        $this->assertTrue($this->schemaManager->tablesExist($tableNameJobs));
+    }
+
+    public function testCanOnlyRunDoctrineDbalMigrationClasses(): void
+    {
+        $migration = new class implements MigrationInterface {
+            public function run(): void
+            {
+            }
+            public function revert(): void
+            {
+            }
+        };
+
+        /** @psalm-suppress InvalidArgument */
+        $migrator = new Migrator($this->connection, $this->loggerServiceMock);
+
+        $migrator->runSetup();
+
+        $this->expectException(InvalidValueException::class);
+
+        $migrator->runMigrationClasses([get_class($migration)]);
+    }
+
+    public function testCanGetImplementedMigrationClasses(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $migrator = new Migrator($this->connection, $this->loggerServiceMock);
+
+        $migrator->runSetup();
+
+        $this->assertEmpty($migrator->getImplementedMigrationClasses());
+
+        $migrator->runNonImplementedMigrationClasses(
+            $this->getSampleMigrationsDirectory(),
+            $this->getSampleNameSpace()
+        );
+
+        $this->assertNotEmpty($migrator->getImplementedMigrationClasses());
+    }
+
+    public function testThrowsStoreExceptionOnInitialization(): void
+    {
+        $dbalStub = $this->createStub(\Doctrine\DBAL\Connection::class);
+        $dbalStub->method('createSchemaManager')->willThrowException(new \Doctrine\DBAL\Exception('test'));
+        $connectionStub = $this->createStub(Connection::class);
+        $connectionStub->method('dbal')->willReturn($dbalStub);
+
+        $this->expectException(StoreException::class);
+
+        /** @psalm-suppress InvalidArgument */
+        (new Migrator($connectionStub, $this->loggerServiceMock));
+    }
+
+    public function testThrowsStoreExceptionOnNeedsSetup(): void
+    {
+        $schemaManagerStub = $this->createStub(AbstractSchemaManager::class);
+        $schemaManagerStub->method('tablesExist')
+            ->willThrowException(new \Doctrine\DBAL\Exception('test'));
+        $dbalStub = $this->createStub(\Doctrine\DBAL\Connection::class);
+        $dbalStub->method('createSchemaManager')->willReturn($schemaManagerStub);
+        $connectionStub = $this->createStub(Connection::class);
+        $connectionStub->method('dbal')->willReturn($dbalStub);
+
+        /** @psalm-suppress InvalidArgument */
+        $migrator = new Migrator($connectionStub, $this->loggerServiceMock);
+
+        $this->expectException(StoreException::class);
+
+        $migrator->needsSetup();
+    }
+
+    public function testThrowsStoreExceptionOnCreateMigrationsTable(): void
+    {
+        $schemaManagerStub = $this->createStub(AbstractSchemaManager::class);
+        $schemaManagerStub->method('tablesExist')
+            ->willReturn(false);
+        $dbalStub = $this->createStub(\Doctrine\DBAL\Connection::class);
+        $dbalStub->method('createSchemaManager')->willReturn($schemaManagerStub);
+        $connectionStub = $this->createStub(Connection::class);
+        $connectionStub->method('dbal')->willReturn($dbalStub);
+
+        /** @psalm-suppress InvalidArgument */
+        $migrator = new Migrator($connectionStub, $this->loggerServiceMock);
+
+        $this->expectException(StoreException::class);
+
+        $migrator->runSetup();
+    }
+
+    public function testThrowsStoreExceptionOnMarkingImplementedClass(): void
+    {
+        $queryBuilderStub = $this->createStub(QueryBuilder::class);
+        $queryBuilderStub->method('insert')
+            ->willThrowException(new \Doctrine\DBAL\Exception('test'));
+        $dbalStub = $this->createStub(\Doctrine\DBAL\Connection::class);
+        $dbalStub->method('createQueryBuilder')->willReturn($queryBuilderStub);
+        $connectionStub = $this->createStub(Connection::class);
+        $connectionStub->method('dbal')->willReturn($dbalStub);
+        $connectionStub->method('preparePrefixedTableName')->willReturn(Migrator::TABLE_NAME);
+
+        /** @psalm-suppress InvalidArgument */
+        $migrator = new Migrator($connectionStub, $this->loggerServiceMock);
+        $migrator->runSetup();
+
+        $this->expectException(StoreException::class);
+
+        $migrator->runMigrationClasses([Store\Migrations\Version20220601000000CreateJobTable::class]);
+    }
+
+    public function testThrowsStoreExceptionOnGetImplementedMigrationClasses(): void
+    {
+        $schemaManagerStub = $this->createStub(AbstractSchemaManager::class);
+        $dbalStub = $this->createStub(\Doctrine\DBAL\Connection::class);
+        $dbalStub->method('createQueryBuilder')->willThrowException(new \Doctrine\DBAL\Exception('test'));
+        $dbalStub->method('createSchemaManager')->willReturn($schemaManagerStub);
+        $connectionStub = $this->createStub(Connection::class);
+        $connectionStub->method('dbal')->willReturn($dbalStub);
+
+        $this->expectException(StoreException::class);
+
+        /** @psalm-suppress InvalidArgument */
+        (new Migrator($connectionStub, $this->loggerServiceMock))->getImplementedMigrationClasses();
+    }
+
+    protected function getSampleMigrationsDirectory(): string
+    {
+        return $this->moduleConfiguration->getModuleSourceDirectory() . DIRECTORY_SEPARATOR .
+            'Stores' . DIRECTORY_SEPARATOR . 'Jobs' . DIRECTORY_SEPARATOR . 'DoctrineDbal' . DIRECTORY_SEPARATOR .
+            'Store' . DIRECTORY_SEPARATOR . AbstractMigrator::DEFAULT_MIGRATIONS_DIRECTORY_NAME;
+    }
+
+    protected function getSampleNameSpace(): string
+    {
+        return Store::class . '\\' . AbstractMigrator::DEFAULT_MIGRATIONS_DIRECTORY_NAME;
+    }
+}
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/HashDecoratedStateTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/HashDecoratedStateTest.php
new file mode 100644
index 0000000..23cb877
--- /dev/null
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/HashDecoratedStateTest.php
@@ -0,0 +1,71 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store;
+
+use SimpleSAML\Module\accounting\Entities\Authentication\State;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\HashDecoratedState;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\HashDecoratedState
+ * @uses \SimpleSAML\Module\accounting\Helpers\HashHelper
+ * @uses \SimpleSAML\Module\accounting\Helpers\ArrayHelper
+ * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
+ */
+class HashDecoratedStateTest extends TestCase
+{
+    /**
+     * @var \PHPUnit\Framework\MockObject\Stub|State|State&\PHPUnit\Framework\MockObject\Stub
+     */
+    protected $stateStub;
+    protected string $identityProviderEntityId;
+    /**
+     * @var string[]
+     */
+    protected array $identityProviderMetadata;
+    protected string $serviceProviderEntityId;
+    /**
+     * @var string[]
+     */
+    protected array $serviceProviderMetadata;
+    /**
+     * @var string[]
+     */
+    protected array $attributes;
+
+    protected function setUp(): void
+    {
+        $this->stateStub = $this->createStub(State::class);
+        $this->identityProviderEntityId = 'idpEntityId';
+        $this->stateStub->method('getIdentityProviderEntityId')->willReturn($this->identityProviderEntityId);
+        $this->identityProviderMetadata = ['idp' => 'metadata'];
+        $this->stateStub->method('getIdentityProviderMetadata')->willReturn($this->identityProviderMetadata);
+        $this->serviceProviderEntityId = 'spEntityId';
+        $this->stateStub->method('getServiceProviderEntityId')->willReturn($this->serviceProviderEntityId);
+        $this->serviceProviderMetadata = ['sp' => 'metadata'];
+        $this->stateStub->method('getServiceProviderMetadata')->willReturn($this->serviceProviderMetadata);
+        $this->attributes = ['sample' => 'attribute'];
+        $this->stateStub->method('getAttributes')->willReturn($this->attributes);
+    }
+
+    public function testCanCreateInstance(): void
+    {
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $this->assertInstanceOf(HashDecoratedState::class, new HashDecoratedState($this->stateStub));
+    }
+
+    public function testCanGetHashedProperties(): void
+    {
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $hashDecoratedState = new HashDecoratedState($this->stateStub);
+
+        $this->assertSame($this->stateStub, $hashDecoratedState->getState());
+        $this->assertIsString($hashDecoratedState->getIdentityProviderEntityIdHashSha256());
+        $this->assertIsString($hashDecoratedState->getServiceProviderEntityIdHashSha256());
+        $this->assertIsString($hashDecoratedState->getIdentityProviderMetadataArrayHashSha256());
+        $this->assertIsString($hashDecoratedState->getServiceProviderMetadataArrayHashSha256());
+        $this->assertIsString($hashDecoratedState->getAttributesArrayHashSha256());
+    }
+}
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000000CreateIdpTableTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000000CreateIdpTableTest.php
new file mode 100644
index 0000000..2b99a61
--- /dev/null
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000000CreateIdpTableTest.php
@@ -0,0 +1,84 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations;
+
+use Doctrine\DBAL\Schema\AbstractSchemaManager;
+use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations;
+use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000000CreateIdpTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection
+ */
+class Version20220801000000CreateIdpTableTest extends TestCase
+{
+    protected Connection $connection;
+    protected \Doctrine\DBAL\Schema\AbstractSchemaManager $schemaManager;
+    protected string $tableName;
+    protected \PHPUnit\Framework\MockObject\Stub $connectionStub;
+    protected \PHPUnit\Framework\MockObject\Stub $dbalStub;
+    protected \PHPUnit\Framework\MockObject\Stub $schemaManagerStub;
+
+    protected function setUp(): void
+    {
+        $this->connection = new Connection(ConnectionParameters::DBAL_SQLITE_MEMORY);
+        $this->schemaManager = $this->connection->dbal()->createSchemaManager();
+        $this->tableName = 'vds_idp';
+
+        $this->connectionStub = $this->createStub(Connection::class);
+        $this->dbalStub = $this->createStub(\Doctrine\DBAL\Connection::class);
+        $this->schemaManagerStub = $this->createStub(AbstractSchemaManager::class);
+    }
+
+    public function testCanRunMigration(): void
+    {
+        $this->assertFalse($this->schemaManager->tablesExist($this->tableName));
+        $migration = new Migrations\Version20220801000000CreateIdpTable($this->connection);
+        $migration->run();
+        $this->assertTrue($this->schemaManager->tablesExist($this->tableName));
+        $migration->revert();
+        $this->assertFalse($this->schemaManager->tablesExist($this->tableName));
+    }
+
+    public function testRunThrowsMigrationException(): void
+    {
+        $this->connectionStub->method('preparePrefixedTableName')->willReturn($this->tableName);
+        $this->schemaManagerStub->method('createTable')
+            ->willThrowException(new \Doctrine\DBAL\Exception('test'));
+        $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
+        $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
+
+        /** @psalm-suppress InvalidArgument */
+        $migration = new Migrations\Version20220801000000CreateIdpTable($this->connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->run();
+    }
+
+    public function testRevertThrowsMigrationException(): void
+    {
+        $this->schemaManagerStub->method('dropTable')
+            ->willThrowException(new \Doctrine\DBAL\Exception('test'));
+        $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
+        $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
+
+        /** @psalm-suppress InvalidArgument */
+        $migration = new Migrations\Version20220801000000CreateIdpTable($this->connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->revert();
+    }
+
+    public function testRunThrowsOnIvalidTableNameIdp(): void
+    {
+        $this->connectionStub->method('preparePrefixedTableName')
+            ->willReturnOnConsecutiveCalls(''); // Invalid (empty) name for table
+
+        /** @psalm-suppress InvalidArgument */
+        $migration = new Migrations\Version20220801000000CreateIdpTable($this->connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->run();
+    }
+}
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000100CreateIdpVersionTableTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000100CreateIdpVersionTableTest.php
new file mode 100644
index 0000000..525d7ef
--- /dev/null
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000100CreateIdpVersionTableTest.php
@@ -0,0 +1,84 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations;
+
+use Doctrine\DBAL\Schema\AbstractSchemaManager;
+use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations;
+use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000100CreateIdpVersionTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection *
+ */
+class Version20220801000100CreateIdpVersionTableTest extends TestCase
+{
+    protected Connection $connection;
+    protected \Doctrine\DBAL\Schema\AbstractSchemaManager $schemaManager;
+    protected string $tableName;
+    protected \PHPUnit\Framework\MockObject\Stub $connectionStub;
+    protected \PHPUnit\Framework\MockObject\Stub $dbalStub;
+    protected \PHPUnit\Framework\MockObject\Stub $schemaManagerStub;
+
+    protected function setUp(): void
+    {
+        $this->connection = new Connection(ConnectionParameters::DBAL_SQLITE_MEMORY);
+        $this->schemaManager = $this->connection->dbal()->createSchemaManager();
+        $this->tableName = 'vds_idp_version';
+
+        $this->connectionStub = $this->createStub(Connection::class);
+        $this->dbalStub = $this->createStub(\Doctrine\DBAL\Connection::class);
+        $this->schemaManagerStub = $this->createStub(AbstractSchemaManager::class);
+    }
+
+    public function testCanRunMigration(): void
+    {
+        $this->assertFalse($this->schemaManager->tablesExist($this->tableName));
+        $migration = new Migrations\Version20220801000100CreateIdpVersionTable($this->connection);
+        $migration->run();
+        $this->assertTrue($this->schemaManager->tablesExist($this->tableName));
+        $migration->revert();
+        $this->assertFalse($this->schemaManager->tablesExist($this->tableName));
+    }
+
+    public function testRunThrowsMigrationException(): void
+    {
+        $this->connectionStub->method('preparePrefixedTableName')->willReturn($this->tableName);
+        $this->schemaManagerStub->method('createTable')
+            ->willThrowException(new \Doctrine\DBAL\Exception('test'));
+        $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
+        $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
+
+        /** @psalm-suppress InvalidArgument */
+        $migration = new Migrations\Version20220801000100CreateIdpVersionTable($this->connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->run();
+    }
+
+    public function testRevertThrowsMigrationException(): void
+    {
+        $this->schemaManagerStub->method('dropTable')
+            ->willThrowException(new \Doctrine\DBAL\Exception('test'));
+        $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
+        $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
+
+        /** @psalm-suppress InvalidArgument */
+        $migration = new Migrations\Version20220801000100CreateIdpVersionTable($this->connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->revert();
+    }
+
+    public function testRunThrowsOnIvalidTableNameIdp(): void
+    {
+        $this->connectionStub->method('preparePrefixedTableName')
+            ->willReturnOnConsecutiveCalls(''); // Invalid (empty) name for table
+
+        /** @psalm-suppress InvalidArgument */
+        $migration = new Migrations\Version20220801000100CreateIdpVersionTable($this->connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->run();
+    }
+}
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000200CreateSpTableTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000200CreateSpTableTest.php
new file mode 100644
index 0000000..11d7874
--- /dev/null
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000200CreateSpTableTest.php
@@ -0,0 +1,84 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations;
+
+use Doctrine\DBAL\Schema\AbstractSchemaManager;
+use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000200CreateSpTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection *
+ */
+class Version20220801000200CreateSpTableTest extends TestCase
+{
+    protected Connection $connection;
+    protected \Doctrine\DBAL\Schema\AbstractSchemaManager $schemaManager;
+    protected string $tableName;
+    protected \PHPUnit\Framework\MockObject\Stub $connectionStub;
+    protected \PHPUnit\Framework\MockObject\Stub $dbalStub;
+    protected \PHPUnit\Framework\MockObject\Stub $schemaManagerStub;
+
+    protected function setUp(): void
+    {
+        $this->connection = new Connection(ConnectionParameters::DBAL_SQLITE_MEMORY);
+        $this->schemaManager = $this->connection->dbal()->createSchemaManager();
+        $this->tableName = 'vds_sp';
+
+        $this->connectionStub = $this->createStub(Connection::class);
+        $this->dbalStub = $this->createStub(\Doctrine\DBAL\Connection::class);
+        $this->schemaManagerStub = $this->createStub(AbstractSchemaManager::class);
+    }
+
+    public function testCanRunMigration(): void
+    {
+        $this->assertFalse($this->schemaManager->tablesExist($this->tableName));
+        $migration = new Migrations\Version20220801000200CreateSpTable($this->connection);
+        $migration->run();
+        $this->assertTrue($this->schemaManager->tablesExist($this->tableName));
+        $migration->revert();
+        $this->assertFalse($this->schemaManager->tablesExist($this->tableName));
+    }
+
+    public function testRunThrowsMigrationException(): void
+    {
+        $this->connectionStub->method('preparePrefixedTableName')->willReturn($this->tableName);
+        $this->schemaManagerStub->method('createTable')
+            ->willThrowException(new \Doctrine\DBAL\Exception('test'));
+        $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
+        $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
+
+        /** @psalm-suppress InvalidArgument */
+        $migration = new Migrations\Version20220801000200CreateSpTable($this->connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->run();
+    }
+
+    public function testRevertThrowsMigrationException(): void
+    {
+        $this->schemaManagerStub->method('dropTable')
+            ->willThrowException(new \Doctrine\DBAL\Exception('test'));
+        $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
+        $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
+
+        /** @psalm-suppress InvalidArgument */
+        $migration = new Migrations\Version20220801000200CreateSpTable($this->connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->revert();
+    }
+
+    public function testRunThrowsOnIvalidTableNameIdp(): void
+    {
+        $this->connectionStub->method('preparePrefixedTableName')
+            ->willReturnOnConsecutiveCalls(''); // Invalid (empty) name for table
+
+        /** @psalm-suppress InvalidArgument */
+        $migration = new Migrations\Version20220801000200CreateSpTable($this->connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->run();
+    }
+}
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000300CreateSpVersionTableTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000300CreateSpVersionTableTest.php
new file mode 100644
index 0000000..a839507
--- /dev/null
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000300CreateSpVersionTableTest.php
@@ -0,0 +1,84 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations;
+
+use Doctrine\DBAL\Schema\AbstractSchemaManager;
+use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations;
+use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000300CreateSpVersionTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection *
+ */
+class Version20220801000300CreateSpVersionTableTest extends TestCase
+{
+    protected Connection $connection;
+    protected \Doctrine\DBAL\Schema\AbstractSchemaManager $schemaManager;
+    protected string $tableName;
+    protected \PHPUnit\Framework\MockObject\Stub $connectionStub;
+    protected \PHPUnit\Framework\MockObject\Stub $dbalStub;
+    protected \PHPUnit\Framework\MockObject\Stub $schemaManagerStub;
+
+    protected function setUp(): void
+    {
+        $this->connection = new Connection(ConnectionParameters::DBAL_SQLITE_MEMORY);
+        $this->schemaManager = $this->connection->dbal()->createSchemaManager();
+        $this->tableName = 'vds_sp_version';
+
+        $this->connectionStub = $this->createStub(Connection::class);
+        $this->dbalStub = $this->createStub(\Doctrine\DBAL\Connection::class);
+        $this->schemaManagerStub = $this->createStub(AbstractSchemaManager::class);
+    }
+
+    public function testCanRunMigration(): void
+    {
+        $this->assertFalse($this->schemaManager->tablesExist($this->tableName));
+        $migration = new Migrations\Version20220801000300CreateSpVersionTable($this->connection);
+        $migration->run();
+        $this->assertTrue($this->schemaManager->tablesExist($this->tableName));
+        $migration->revert();
+        $this->assertFalse($this->schemaManager->tablesExist($this->tableName));
+    }
+
+    public function testRunThrowsMigrationException(): void
+    {
+        $this->connectionStub->method('preparePrefixedTableName')->willReturn($this->tableName);
+        $this->schemaManagerStub->method('createTable')
+            ->willThrowException(new \Doctrine\DBAL\Exception('test'));
+        $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
+        $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
+
+        /** @psalm-suppress InvalidArgument */
+        $migration = new Migrations\Version20220801000300CreateSpVersionTable($this->connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->run();
+    }
+
+    public function testRevertThrowsMigrationException(): void
+    {
+        $this->schemaManagerStub->method('dropTable')
+            ->willThrowException(new \Doctrine\DBAL\Exception('test'));
+        $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
+        $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
+
+        /** @psalm-suppress InvalidArgument */
+        $migration = new Migrations\Version20220801000300CreateSpVersionTable($this->connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->revert();
+    }
+
+    public function testRunThrowsOnIvalidTableNameIdp(): void
+    {
+        $this->connectionStub->method('preparePrefixedTableName')
+            ->willReturnOnConsecutiveCalls(''); // Invalid (empty) name for table
+
+        /** @psalm-suppress InvalidArgument */
+        $migration = new Migrations\Version20220801000300CreateSpVersionTable($this->connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->run();
+    }
+}
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000400CreateUserTableTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000400CreateUserTableTest.php
new file mode 100644
index 0000000..eca699c
--- /dev/null
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000400CreateUserTableTest.php
@@ -0,0 +1,84 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations;
+
+use Doctrine\DBAL\Schema\AbstractSchemaManager;
+use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations;
+use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000400CreateUserTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection *
+ */
+class Version20220801000400CreateUserTableTest extends TestCase
+{
+    protected Connection $connection;
+    protected \Doctrine\DBAL\Schema\AbstractSchemaManager $schemaManager;
+    protected string $tableName;
+    protected \PHPUnit\Framework\MockObject\Stub $connectionStub;
+    protected \PHPUnit\Framework\MockObject\Stub $dbalStub;
+    protected \PHPUnit\Framework\MockObject\Stub $schemaManagerStub;
+
+    protected function setUp(): void
+    {
+        $this->connection = new Connection(ConnectionParameters::DBAL_SQLITE_MEMORY);
+        $this->schemaManager = $this->connection->dbal()->createSchemaManager();
+        $this->tableName = 'vds_user';
+
+        $this->connectionStub = $this->createStub(Connection::class);
+        $this->dbalStub = $this->createStub(\Doctrine\DBAL\Connection::class);
+        $this->schemaManagerStub = $this->createStub(AbstractSchemaManager::class);
+    }
+
+    public function testCanRunMigration(): void
+    {
+        $this->assertFalse($this->schemaManager->tablesExist($this->tableName));
+        $migration = new Migrations\Version20220801000400CreateUserTable($this->connection);
+        $migration->run();
+        $this->assertTrue($this->schemaManager->tablesExist($this->tableName));
+        $migration->revert();
+        $this->assertFalse($this->schemaManager->tablesExist($this->tableName));
+    }
+
+    public function testRunThrowsMigrationException(): void
+    {
+        $this->connectionStub->method('preparePrefixedTableName')->willReturn($this->tableName);
+        $this->schemaManagerStub->method('createTable')
+            ->willThrowException(new \Doctrine\DBAL\Exception('test'));
+        $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
+        $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
+
+        /** @psalm-suppress InvalidArgument */
+        $migration = new Migrations\Version20220801000400CreateUserTable($this->connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->run();
+    }
+
+    public function testRevertThrowsMigrationException(): void
+    {
+        $this->schemaManagerStub->method('dropTable')
+            ->willThrowException(new \Doctrine\DBAL\Exception('test'));
+        $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
+        $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
+
+        /** @psalm-suppress InvalidArgument */
+        $migration = new Migrations\Version20220801000400CreateUserTable($this->connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->revert();
+    }
+
+    public function testRunThrowsOnIvalidTableNameIdp(): void
+    {
+        $this->connectionStub->method('preparePrefixedTableName')
+            ->willReturnOnConsecutiveCalls(''); // Invalid (empty) name for table
+
+        /** @psalm-suppress InvalidArgument */
+        $migration = new Migrations\Version20220801000400CreateUserTable($this->connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->run();
+    }
+}
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000500CreateUserVersionTableTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000500CreateUserVersionTableTest.php
new file mode 100644
index 0000000..4238489
--- /dev/null
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000500CreateUserVersionTableTest.php
@@ -0,0 +1,84 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations;
+
+use Doctrine\DBAL\Schema\AbstractSchemaManager;
+use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations;
+use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000500CreateUserVersionTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection *
+ */
+class Version20220801000500CreateUserVersionTableTest extends TestCase
+{
+    protected Connection $connection;
+    protected \Doctrine\DBAL\Schema\AbstractSchemaManager $schemaManager;
+    protected string $tableName;
+    protected \PHPUnit\Framework\MockObject\Stub $connectionStub;
+    protected \PHPUnit\Framework\MockObject\Stub $dbalStub;
+    protected \PHPUnit\Framework\MockObject\Stub $schemaManagerStub;
+
+    protected function setUp(): void
+    {
+        $this->connection = new Connection(ConnectionParameters::DBAL_SQLITE_MEMORY);
+        $this->schemaManager = $this->connection->dbal()->createSchemaManager();
+        $this->tableName = 'vds_user_version';
+
+        $this->connectionStub = $this->createStub(Connection::class);
+        $this->dbalStub = $this->createStub(\Doctrine\DBAL\Connection::class);
+        $this->schemaManagerStub = $this->createStub(AbstractSchemaManager::class);
+    }
+
+    public function testCanRunMigration(): void
+    {
+        $this->assertFalse($this->schemaManager->tablesExist($this->tableName));
+        $migration = new Migrations\Version20220801000500CreateUserVersionTable($this->connection);
+        $migration->run();
+        $this->assertTrue($this->schemaManager->tablesExist($this->tableName));
+        $migration->revert();
+        $this->assertFalse($this->schemaManager->tablesExist($this->tableName));
+    }
+
+    public function testRunThrowsMigrationException(): void
+    {
+        $this->connectionStub->method('preparePrefixedTableName')->willReturn($this->tableName);
+        $this->schemaManagerStub->method('createTable')
+            ->willThrowException(new \Doctrine\DBAL\Exception('test'));
+        $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
+        $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
+
+        /** @psalm-suppress InvalidArgument */
+        $migration = new Migrations\Version20220801000500CreateUserVersionTable($this->connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->run();
+    }
+
+    public function testRevertThrowsMigrationException(): void
+    {
+        $this->schemaManagerStub->method('dropTable')
+            ->willThrowException(new \Doctrine\DBAL\Exception('test'));
+        $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
+        $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
+
+        /** @psalm-suppress InvalidArgument */
+        $migration = new Migrations\Version20220801000500CreateUserVersionTable($this->connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->revert();
+    }
+
+    public function testRunThrowsOnIvalidTableNameIdp(): void
+    {
+        $this->connectionStub->method('preparePrefixedTableName')
+            ->willReturnOnConsecutiveCalls(''); // Invalid (empty) name for table
+
+        /** @psalm-suppress InvalidArgument */
+        $migration = new Migrations\Version20220801000500CreateUserVersionTable($this->connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->run();
+    }
+}
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000600CreateIdpSpUserVersionTableTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000600CreateIdpSpUserVersionTableTest.php
new file mode 100644
index 0000000..ce214e6
--- /dev/null
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000600CreateIdpSpUserVersionTableTest.php
@@ -0,0 +1,88 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations;
+
+use Doctrine\DBAL\Schema\AbstractSchemaManager;
+use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations;
+use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000600CreateIdpSpUserVersionTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection *
+ */
+class Version20220801000600CreateIdpSpUserVersionTableTest extends TestCase
+{
+    protected Connection $connection;
+    protected \Doctrine\DBAL\Schema\AbstractSchemaManager $schemaManager;
+    protected string $tableName;
+    protected \PHPUnit\Framework\MockObject\Stub $connectionStub;
+    protected \PHPUnit\Framework\MockObject\Stub $dbalStub;
+    protected \PHPUnit\Framework\MockObject\Stub $schemaManagerStub;
+
+    protected function setUp(): void
+    {
+        $this->connection = new Connection(ConnectionParameters::DBAL_SQLITE_MEMORY);
+        $this->schemaManager = $this->connection->dbal()->createSchemaManager();
+        $this->tableName = 'vds_idp_sp_user_version';
+
+        $this->connectionStub = $this->createStub(Connection::class);
+        $this->dbalStub = $this->createStub(\Doctrine\DBAL\Connection::class);
+        $this->schemaManagerStub = $this->createStub(AbstractSchemaManager::class);
+    }
+
+    public function testCanRunMigration(): void
+    {
+        $this->assertFalse($this->schemaManager->tablesExist($this->tableName));
+        $migration =
+            new Migrations\Version20220801000600CreateIdpSpUserVersionTable($this->connection);
+        $migration->run();
+        $this->assertTrue($this->schemaManager->tablesExist($this->tableName));
+        $migration->revert();
+        $this->assertFalse($this->schemaManager->tablesExist($this->tableName));
+    }
+
+    public function testRunThrowsMigrationException(): void
+    {
+        $this->connectionStub->method('preparePrefixedTableName')->willReturn($this->tableName);
+        $this->schemaManagerStub->method('createTable')
+            ->willThrowException(new \Doctrine\DBAL\Exception('test'));
+        $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
+        $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
+
+        /** @psalm-suppress InvalidArgument */
+        $migration =
+            new Migrations\Version20220801000600CreateIdpSpUserVersionTable($this->connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->run();
+    }
+
+    public function testRevertThrowsMigrationException(): void
+    {
+        $this->schemaManagerStub->method('dropTable')
+            ->willThrowException(new \Doctrine\DBAL\Exception('test'));
+        $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
+        $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
+
+        /** @psalm-suppress InvalidArgument */
+        $migration =
+            new Migrations\Version20220801000600CreateIdpSpUserVersionTable($this->connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->revert();
+    }
+
+    public function testRunThrowsOnIvalidTableNameIdp(): void
+    {
+        $this->connectionStub->method('preparePrefixedTableName')
+            ->willReturnOnConsecutiveCalls(''); // Invalid (empty) name for table
+
+        /** @psalm-suppress InvalidArgument */
+        $migration =
+            new Migrations\Version20220801000600CreateIdpSpUserVersionTable($this->connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->run();
+    }
+}
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000700CreateAuthenticationEventTableTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000700CreateAuthenticationEventTableTest.php
new file mode 100644
index 0000000..004b192
--- /dev/null
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/Migrations/Version20220801000700CreateAuthenticationEventTableTest.php
@@ -0,0 +1,84 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations;
+
+use Doctrine\DBAL\Schema\AbstractSchemaManager;
+use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations;
+use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000700CreateAuthenticationEventTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection *
+ */
+class Version20220801000700CreateAuthenticationEventTableTest extends TestCase
+{
+    protected Connection $connection;
+    protected \Doctrine\DBAL\Schema\AbstractSchemaManager $schemaManager;
+    protected string $tableName;
+    protected \PHPUnit\Framework\MockObject\Stub $connectionStub;
+    protected \PHPUnit\Framework\MockObject\Stub $dbalStub;
+    protected \PHPUnit\Framework\MockObject\Stub $schemaManagerStub;
+
+    protected function setUp(): void
+    {
+        $this->connection = new Connection(ConnectionParameters::DBAL_SQLITE_MEMORY);
+        $this->schemaManager = $this->connection->dbal()->createSchemaManager();
+        $this->tableName = 'vds_authentication_event';
+
+        $this->connectionStub = $this->createStub(Connection::class);
+        $this->dbalStub = $this->createStub(\Doctrine\DBAL\Connection::class);
+        $this->schemaManagerStub = $this->createStub(AbstractSchemaManager::class);
+    }
+
+    public function testCanRunMigration(): void
+    {
+        $this->assertFalse($this->schemaManager->tablesExist($this->tableName));
+        $migration = new Migrations\Version20220801000700CreateAuthenticationEventTable($this->connection);
+        $migration->run();
+        $this->assertTrue($this->schemaManager->tablesExist($this->tableName));
+        $migration->revert();
+        $this->assertFalse($this->schemaManager->tablesExist($this->tableName));
+    }
+
+    public function testRunThrowsMigrationException(): void
+    {
+        $this->connectionStub->method('preparePrefixedTableName')->willReturn($this->tableName);
+        $this->schemaManagerStub->method('createTable')
+            ->willThrowException(new \Doctrine\DBAL\Exception('test'));
+        $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
+        $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
+
+        /** @psalm-suppress InvalidArgument */
+        $migration = new Migrations\Version20220801000700CreateAuthenticationEventTable($this->connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->run();
+    }
+
+    public function testRevertThrowsMigrationException(): void
+    {
+        $this->schemaManagerStub->method('dropTable')
+            ->willThrowException(new \Doctrine\DBAL\Exception('test'));
+        $this->dbalStub->method('createSchemaManager')->willReturn($this->schemaManagerStub);
+        $this->connectionStub->method('dbal')->willReturn($this->dbalStub);
+
+        /** @psalm-suppress InvalidArgument */
+        $migration = new Migrations\Version20220801000700CreateAuthenticationEventTable($this->connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->revert();
+    }
+
+    public function testRunThrowsOnIvalidTableNameIdp(): void
+    {
+        $this->connectionStub->method('preparePrefixedTableName')
+            ->willReturnOnConsecutiveCalls(''); // Invalid (empty) name for table
+
+        /** @psalm-suppress InvalidArgument */
+        $migration = new Migrations\Version20220801000700CreateAuthenticationEventTable($this->connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->run();
+    }
+}
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawActivityTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawActivityTest.php
new file mode 100644
index 0000000..5c9febc
--- /dev/null
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawActivityTest.php
@@ -0,0 +1,146 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store;
+
+use Doctrine\DBAL\Platforms\AbstractPlatform;
+use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\RawActivity;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\TableConstants;
+use SimpleSAML\Test\Module\accounting\Constants\DateTime;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\RawActivity
+ * @uses \SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractRawEntity
+ */
+class RawActivityTest extends TestCase
+{
+    /**
+     * @var string[]
+     */
+    protected array $serviceProviderMetadata;
+    /**
+     * @var string[]
+     */
+    protected array $userAttributes;
+    protected string $happenedAt;
+    protected string $clientIpAddress;
+
+    protected array $rawRow;
+    /**
+     * @var AbstractPlatform|AbstractPlatform&\PHPUnit\Framework\MockObject\Stub|\PHPUnit\Framework\MockObject\Stub
+     */
+    protected $abstractPlatformStub;
+
+    protected function setUp(): void
+    {
+        $this->serviceProviderMetadata = ['sp' => 'metadata'];
+        $this->userAttributes = ['user' => 'attribute'];
+        $this->happenedAt = '2022-02-22 22:22:22';
+        $this->clientIpAddress = '123.123.123.123';
+
+        $this->rawRow = [
+            TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_SP_METADATA => serialize($this->serviceProviderMetadata),
+            TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_USER_ATTRIBUTES => serialize($this->userAttributes),
+            TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_HAPPENED_AT => $this->happenedAt,
+            TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_CLIENT_IP_ADDRESS => $this->clientIpAddress,
+        ];
+        $this->abstractPlatformStub = $this->createStub(AbstractPlatform::class);
+        $this->abstractPlatformStub->method('getDateTimeFormatString')->willReturn(DateTime::DEFAULT_FORMAT);
+    }
+
+    public function testCanCreateInstance(): void
+    {
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $rawActivity = new RawActivity($this->rawRow, $this->abstractPlatformStub);
+
+        $this->assertInstanceOf(RawActivity::class, $rawActivity);
+    }
+
+    public function testCanGetProperties(): void
+    {
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $rawActivity = new RawActivity($this->rawRow, $this->abstractPlatformStub);
+
+        $this->assertInstanceOf(\DateTimeImmutable::class, $rawActivity->getHappenedAt());
+        $this->assertSame($this->serviceProviderMetadata, $rawActivity->getServiceProviderMetadata());
+        $this->assertSame($this->userAttributes, $rawActivity->getUserAttributes());
+        $this->assertSame($this->clientIpAddress, $rawActivity->getClientIpAddress());
+    }
+
+    public function testIpAddressCanBeMissing(): void
+    {
+        $rawRow = $this->rawRow;
+        unset($rawRow[TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_CLIENT_IP_ADDRESS]);
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $rawActivity = new RawActivity($rawRow, $this->abstractPlatformStub);
+        $this->assertNull($rawActivity->getClientIpAddress());
+    }
+
+    public function testThrowsIfColumnNotPresent(): void
+    {
+        $rawRow = $this->rawRow;
+        unset($rawRow[TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_HAPPENED_AT]);
+
+        $this->expectException(UnexpectedValueException::class);
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        new RawActivity($rawRow, $this->abstractPlatformStub);
+    }
+
+    public function testThrowsForNonStringServiceProviderMetadata(): void
+    {
+        $rawRow = $this->rawRow;
+        $rawRow[TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_SP_METADATA] = 1;
+
+        $this->expectException(UnexpectedValueException::class);
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        new RawActivity($rawRow, $this->abstractPlatformStub);
+    }
+
+    public function testThrowsForNonStringUserAttributes(): void
+    {
+        $rawRow = $this->rawRow;
+        $rawRow[TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_USER_ATTRIBUTES] = 1;
+
+        $this->expectException(UnexpectedValueException::class);
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        new RawActivity($rawRow, $this->abstractPlatformStub);
+    }
+
+    public function testThrowsForNonStringHappenedAt(): void
+    {
+        $rawRow = $this->rawRow;
+        $rawRow[TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_HAPPENED_AT] = 1;
+
+        $this->expectException(UnexpectedValueException::class);
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        new RawActivity($rawRow, $this->abstractPlatformStub);
+    }
+
+    public function testThrowsForInvalidServiceProviderMetadata(): void
+    {
+        $rawRow = $this->rawRow;
+        $rawRow[TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_SP_METADATA] = serialize(1);
+
+        $this->expectException(UnexpectedValueException::class);
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        new RawActivity($rawRow, $this->abstractPlatformStub);
+    }
+
+    public function testThrowsForInvalidUserAttributes(): void
+    {
+        $rawRow = $this->rawRow;
+        $rawRow[TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_USER_ATTRIBUTES] = serialize(1);
+
+        $this->expectException(UnexpectedValueException::class);
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        new RawActivity($rawRow, $this->abstractPlatformStub);
+    }
+}
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawConnectedServiceProviderTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawConnectedServiceProviderTest.php
new file mode 100644
index 0000000..68fe4ed
--- /dev/null
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RawConnectedServiceProviderTest.php
@@ -0,0 +1,177 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store;
+
+use Doctrine\DBAL\Platforms\AbstractPlatform;
+use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\RawConnectedServiceProvider;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\TableConstants;
+use SimpleSAML\Test\Module\accounting\Constants\DateTime;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\RawConnectedServiceProvider
+ * @uses \SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractRawEntity
+ */
+class RawConnectedServiceProviderTest extends TestCase
+{
+    protected int $numberOfAuthentications;
+    protected string $lastAuthenticationAt;
+    protected string $firstAuthenticationAt;
+    /**
+     * @var string[]
+     */
+    protected array $serviceProviderMetadata;
+    /**
+     * @var string[]
+     */
+    protected array $userAttributes;
+    protected array $rawRow;
+    /**
+     * @var AbstractPlatform|AbstractPlatform&\PHPUnit\Framework\MockObject\Stub|\PHPUnit\Framework\MockObject\Stub
+     */
+    protected $abstractPlatformStub;
+    protected string $dateTimeFormat;
+
+    protected function setUp(): void
+    {
+        $this->numberOfAuthentications = 2;
+        $this->lastAuthenticationAt = '2022-02-22 22:22:22';
+        $this->firstAuthenticationAt = '2022-02-02 22:22:22';
+        $this->serviceProviderMetadata = ['sp' => 'metadata'];
+        $this->userAttributes = ['user' => 'attribute'];
+        $this->rawRow = [
+            TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_NUMBER_OF_AUTHENTICATIONS =>
+                $this->numberOfAuthentications,
+            TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_LAST_AUTHENTICATION_AT =>
+                $this->lastAuthenticationAt,
+            TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_FIRST_AUTHENTICATION_AT =>
+                $this->firstAuthenticationAt,
+            TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_SP_METADATA =>
+                serialize($this->serviceProviderMetadata),
+            TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_USER_ATTRIBUTES =>
+                serialize($this->userAttributes),
+        ];
+        $this->dateTimeFormat = DateTime::DEFAULT_FORMAT;
+        $this->abstractPlatformStub = $this->createStub(AbstractPlatform::class);
+        $this->abstractPlatformStub->method('getDateTimeFormatString')
+            ->willReturn($this->dateTimeFormat);
+    }
+
+    public function testCanCreateInstance(): void
+    {
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $this->assertInstanceOf(
+            RawConnectedServiceProvider::class,
+            new RawConnectedServiceProvider($this->rawRow, $this->abstractPlatformStub)
+        );
+    }
+
+    public function testCanGetProperties(): void
+    {
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $rawConnectedServiceProvider = new RawConnectedServiceProvider($this->rawRow, $this->abstractPlatformStub);
+
+        $this->assertSame($this->numberOfAuthentications, $rawConnectedServiceProvider->getNumberOfAuthentications());
+        $this->assertInstanceOf(\DateTimeImmutable::class, $rawConnectedServiceProvider->getLastAuthenticationAt());
+        $this->assertSame(
+            $this->lastAuthenticationAt,
+            $rawConnectedServiceProvider->getLastAuthenticationAt()->format($this->dateTimeFormat)
+        );
+        $this->assertInstanceOf(\DateTimeImmutable::class, $rawConnectedServiceProvider->getFirstAuthenticationAt());
+        $this->assertSame(
+            $this->firstAuthenticationAt,
+            $rawConnectedServiceProvider->getFirstAuthenticationAt()->format($this->dateTimeFormat)
+        );
+        $this->assertSame($this->serviceProviderMetadata, $rawConnectedServiceProvider->getServiceProviderMetadata());
+        $this->assertSame($this->userAttributes, $rawConnectedServiceProvider->getUserAttributes());
+    }
+
+    public function testThrowsIfColumnNotSet(): void
+    {
+        $rawRow = $this->rawRow;
+        unset($rawRow[TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_USER_ATTRIBUTES]);
+
+        $this->expectException(UnexpectedValueException::class);
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        new RawConnectedServiceProvider($rawRow, $this->abstractPlatformStub);
+    }
+
+    public function testThrowsIfNumberOfAuthenticationsNotNumeric(): void
+    {
+        $rawRow = $this->rawRow;
+        $rawRow[TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_NUMBER_OF_AUTHENTICATIONS] = 'a';
+
+        $this->expectException(UnexpectedValueException::class);
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        new RawConnectedServiceProvider($rawRow, $this->abstractPlatformStub);
+    }
+
+    public function testThrowsIfLastAuthenticationAtNotString(): void
+    {
+        $rawRow = $this->rawRow;
+        $rawRow[TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_LAST_AUTHENTICATION_AT] = 1;
+
+        $this->expectException(UnexpectedValueException::class);
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        new RawConnectedServiceProvider($rawRow, $this->abstractPlatformStub);
+    }
+
+    public function testThrowsIfFirstAuthenticationAtNotString(): void
+    {
+        $rawRow = $this->rawRow;
+        $rawRow[TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_FIRST_AUTHENTICATION_AT] = 1;
+
+        $this->expectException(UnexpectedValueException::class);
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        new RawConnectedServiceProvider($rawRow, $this->abstractPlatformStub);
+    }
+
+    public function testThrowsIfSpMetadataNotString(): void
+    {
+        $rawRow = $this->rawRow;
+        $rawRow[TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_SP_METADATA] = 1;
+
+        $this->expectException(UnexpectedValueException::class);
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        new RawConnectedServiceProvider($rawRow, $this->abstractPlatformStub);
+    }
+
+    public function testThrowsIfUserAttributesNotString(): void
+    {
+        $rawRow = $this->rawRow;
+        $rawRow[TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_USER_ATTRIBUTES] = 1;
+
+        $this->expectException(UnexpectedValueException::class);
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        new RawConnectedServiceProvider($rawRow, $this->abstractPlatformStub);
+    }
+
+    public function testThrowsIfSpMetadataNotValid(): void
+    {
+        $rawRow = $this->rawRow;
+        $rawRow[TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_SP_METADATA] = serialize(1);
+
+        $this->expectException(UnexpectedValueException::class);
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        new RawConnectedServiceProvider($rawRow, $this->abstractPlatformStub);
+    }
+
+    public function testThrowsIfUserAttributesNotValid(): void
+    {
+        $rawRow = $this->rawRow;
+        $rawRow[TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_USER_ATTRIBUTES] = serialize(1);
+
+        $this->expectException(UnexpectedValueException::class);
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        new RawConnectedServiceProvider($rawRow, $this->abstractPlatformStub);
+    }
+}
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RepositoryTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RepositoryTest.php
new file mode 100644
index 0000000..63144f4
--- /dev/null
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/Store/RepositoryTest.php
@@ -0,0 +1,789 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store;
+
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Module\accounting\Exceptions\StoreException;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Stores\Connections\Bases\AbstractMigrator;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Repository;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
+use SimpleSAML\Test\Module\accounting\Constants\DateTime;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Repository
+ * @uses \SimpleSAML\Module\accounting\Helpers\FilesystemHelper
+ * @uses \SimpleSAML\Module\accounting\ModuleConfiguration
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\Bases\AbstractMigrator
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000000CreateIdpTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000100CreateIdpVersionTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000200CreateSpTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000300CreateSpVersionTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000400CreateUserTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000500CreateUserVersionTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000600CreateIdpSpUserVersionTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000700CreateAuthenticationEventTable
+ * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
+ *
+ * @psalm-suppress all
+ */
+class RepositoryTest extends TestCase
+{
+    protected Connection $connection;
+    protected \Doctrine\DBAL\Connection $dbal;
+    /**
+     * @var \PHPUnit\Framework\MockObject\Stub|LoggerInterface|LoggerInterface&\PHPUnit\Framework\MockObject\Stub
+     */
+    protected $loggerStub;
+    protected Migrator $migrator;
+    protected string $dateTimeFormat;
+    protected string $idpEntityId;
+    protected string $idpEntityIdHash;
+    protected string $idpMetadata;
+    protected string $idpMetadataHash;
+    protected string $spEntityId;
+    protected string $spMetadataHash;
+    protected string $userIdentifier;
+    protected string $userIdentifierHash;
+    protected string $userAttributes;
+    protected string $userAttributesHash;
+    protected Repository $repository;
+    protected \DateTimeImmutable $createdAt;
+    /**
+     * @var \PHPUnit\Framework\MockObject\Stub|Connection|Connection&\PHPUnit\Framework\MockObject\Stub
+     */
+    protected $connectionStub;
+    protected string $spEntityIdHash;
+    protected string $spMetadata;
+    protected string $clientIpAddress;
+
+    protected function setUp(): void
+    {
+        // For stubbing.
+        $this->connectionStub = $this->createStub(Connection::class);
+        $this->loggerStub = $this->createStub(LoggerInterface::class);
+
+        // For real DB testing.
+        $connectionParameters = ConnectionParameters::DBAL_SQLITE_MEMORY;
+        $this->connection = new Connection($connectionParameters);
+        $this->migrator = new Migrator($this->connection, $this->loggerStub);
+        $moduleConfiguration = new ModuleConfiguration();
+        $migrationsDirectory = $moduleConfiguration->getModuleSourceDirectory() . DIRECTORY_SEPARATOR . 'Stores' .
+            DIRECTORY_SEPARATOR . 'Data' . DIRECTORY_SEPARATOR . 'Authentication' . DIRECTORY_SEPARATOR .
+            'DoctrineDbal' . DIRECTORY_SEPARATOR . 'Versioned' . DIRECTORY_SEPARATOR . 'Store' . DIRECTORY_SEPARATOR .
+            AbstractMigrator::DEFAULT_MIGRATIONS_DIRECTORY_NAME;
+        $namespace = Store::class . '\\' . AbstractMigrator::DEFAULT_MIGRATIONS_DIRECTORY_NAME;
+
+        $this->migrator->runSetup();
+        $this->migrator->runNonImplementedMigrationClasses($migrationsDirectory, $namespace);
+
+        $this->repository = new Repository($this->connection, $this->loggerStub);
+
+        $this->dateTimeFormat = DateTime::DEFAULT_FORMAT;
+
+        $this->idpEntityId = 'idp-entity-id';
+        $this->idpEntityIdHash = 'idp-entity-id-hash';
+
+        $this->idpMetadata = 'idp-metadata';
+        $this->idpMetadataHash = 'idp-metadata-hash';
+
+        $this->spEntityId = 'sp-entity-id';
+        $this->spEntityIdHash = 'sp-entity-id-hash';
+
+        $this->spMetadata = 'sp-metadata';
+        $this->spMetadataHash = 'sp-metadata-hash';
+
+        $this->userIdentifier = 'user-identifier';
+        $this->userIdentifierHash = 'user-identifier-hash';
+
+        $this->userAttributes = 'user-attributes';
+        $this->userAttributesHash = 'user-attributes-hash';
+
+        $this->createdAt = new \DateTimeImmutable();
+        $this->clientIpAddress = '123.123.123.123';
+    }
+
+    public function testCanCreateInstance(): void
+    {
+        $this->assertInstanceOf(
+            Repository::class,
+            new Repository($this->connection, $this->loggerStub)
+        );
+    }
+
+    public function testCanInsertAndGetIdp(): array
+    {
+        $this->repository->insertIdp($this->idpEntityId, $this->idpEntityIdHash, $this->createdAt);
+
+        $result = $this->repository->getIdp($this->idpEntityIdHash)->fetchAssociative();
+
+        $this->assertSame($this->idpEntityId, $result[Store\TableConstants::TABLE_IDP_COLUMN_NAME_ENTITY_ID]);
+        $this->assertSame(
+            $this->idpEntityIdHash,
+            $result[Store\TableConstants::TABLE_IDP_COLUMN_NAME_ENTITY_ID_HASH_SHA256]
+        );
+        $this->assertSame(
+            $this->createdAt->format($this->dateTimeFormat),
+            $result[Store\TableConstants::TABLE_IDP_COLUMN_NAME_CREATED_AT]
+        );
+
+        return $result;
+    }
+
+    public function testInsertIdpThrowsOnNonUniqueIdpEntityIdHash(): void
+    {
+        $this->expectException(StoreException::class);
+
+        // Can't insert duplicate idp entity ID hash.
+        $this->repository->insertIdp($this->idpEntityId, $this->idpEntityIdHash, $this->createdAt);
+        $this->repository->insertIdp($this->idpEntityId, $this->idpEntityIdHash, $this->createdAt);
+    }
+
+    public function testGetIdpThrowsOnInvalidDbal(): void
+    {
+        $this->connectionStub->method('dbal')->willThrowException(new \Exception('test'));
+        $repository = new Repository($this->connectionStub, $this->loggerStub);
+        $this->expectException(StoreException::class);
+
+        $repository->getIdp($this->idpEntityIdHash);
+    }
+
+    /**
+     * @depends testCanInsertAndGetIdp
+     */
+    public function testCanInsertAndGetIdpVersion(array $idpResult): array
+    {
+        $idpId = (int)$idpResult[Store\TableConstants::TABLE_IDP_COLUMN_NAME_ID];
+
+        $this->repository->insertIdpVersion($idpId, $this->idpMetadata, $this->idpMetadataHash, $this->createdAt);
+
+        $result = $this->repository->getIdpVersion($idpId, $this->idpMetadataHash)->fetchAssociative();
+
+        $this->assertSame($this->idpMetadata, $result[Store\TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_METADATA]);
+        $this->assertSame(
+            $this->idpMetadataHash,
+            $result[Store\TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_METADATA_HASH_SHA256]
+        );
+        $this->assertSame(
+            $this->createdAt->format($this->dateTimeFormat),
+            $result[Store\TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_CREATED_AT]
+        );
+
+        return $result;
+    }
+
+    public function testInsertIdpVersionThrowsOnNonUniqueIdpMetadataHash(): void
+    {
+        $this->expectException(StoreException::class);
+        // IdP Metadata Hash must be unique.
+        $this->repository->insertIdpVersion(1, $this->idpMetadata, $this->idpMetadataHash, $this->createdAt);
+        $this->repository->insertIdpVersion(1, $this->idpMetadata, $this->idpMetadataHash, $this->createdAt);
+    }
+
+    public function testGetIdpVersionThrowsOnInvalidDbal(): void
+    {
+        $this->connectionStub->method('dbal')->willThrowException(new \Exception('test'));
+        $repository = new Repository($this->connectionStub, $this->loggerStub);
+        $this->expectException(StoreException::class);
+
+        $repository->getIdpVersion(1, $this->idpMetadataHash);
+    }
+
+    public function testCanInsertAndGetSp(): array
+    {
+        $this->repository->insertSp($this->spEntityId, $this->spEntityIdHash, $this->createdAt);
+
+        $result = $this->repository->getSp($this->spEntityIdHash)->fetchAssociative();
+
+        $this->assertSame($this->spEntityId, $result[Store\TableConstants::TABLE_SP_COLUMN_NAME_ENTITY_ID]);
+        $this->assertSame(
+            $this->spEntityIdHash,
+            $result[Store\TableConstants::TABLE_SP_COLUMN_NAME_ENTITY_ID_HASH_SHA256]
+        );
+        $this->assertSame(
+            $this->createdAt->format($this->dateTimeFormat),
+            $result[Store\TableConstants::TABLE_SP_COLUMN_NAME_CREATED_AT]
+        );
+
+        return $result;
+    }
+
+    public function testInsertSpThrowsOnNonUniqueSpEntityIdHash(): void
+    {
+        $this->expectException(StoreException::class);
+        // SP Entity ID Hash must be unique.
+        $this->repository->insertSp($this->spEntityId, $this->spEntityIdHash, $this->createdAt);
+        $this->repository->insertSp($this->spEntityId, $this->spEntityIdHash, $this->createdAt);
+    }
+
+    public function testGetSpThrowsOnInvalidDbal(): void
+    {
+        $this->connectionStub->method('dbal')->willThrowException(new \Exception('test'));
+        $repository = new Repository($this->connectionStub, $this->loggerStub);
+        $this->expectException(StoreException::class);
+
+        $repository->getSp($this->spEntityIdHash);
+    }
+
+    /**
+     * @depends testCanInsertAndGetSp
+     */
+    public function testCanInsertAndGetSpVersion(array $spResult): array
+    {
+        $spId = (int)$spResult[Store\TableConstants::TABLE_SP_COLUMN_NAME_ID];
+
+        $this->repository->insertSpVersion($spId, $this->spMetadata, $this->spMetadataHash, $this->createdAt);
+
+        $result = $this->repository->getSpVersion($spId, $this->spMetadataHash)->fetchAssociative();
+
+        $this->assertSame($this->spMetadata, $result[Store\TableConstants::TABLE_SP_VERSION_COLUMN_NAME_METADATA]);
+        $this->assertSame(
+            $this->spMetadataHash,
+            $result[Store\TableConstants::TABLE_SP_VERSION_COLUMN_NAME_METADATA_HASH_SHA256]
+        );
+        $this->assertSame(
+            $this->createdAt->format($this->dateTimeFormat),
+            $result[Store\TableConstants::TABLE_SP_VERSION_COLUMN_NAME_CREATED_AT]
+        );
+
+        return $result;
+    }
+
+    public function testInsertSpVersionThrowsOnNonUniqueMetadataHash(): void
+    {
+        $this->expectException(StoreException::class);
+        // SP metadata hash must be unique.
+        $this->repository->insertSpVersion(1, $this->spMetadata, $this->spMetadataHash, $this->createdAt);
+        $this->repository->insertSpVersion(1, $this->spMetadata, $this->spMetadataHash, $this->createdAt);
+    }
+
+    public function testGetSpVersionThrowsOnInvalidDbal(): void
+    {
+        $this->connectionStub->method('dbal')->willThrowException(new \Exception('test'));
+        $repository = new Repository($this->connectionStub, $this->loggerStub);
+        $this->expectException(StoreException::class);
+
+        $repository->getSpVersion(1, $this->spMetadataHash);
+    }
+
+    public function testCanInsertAndGetUser(): array
+    {
+        $this->repository->insertUser($this->userIdentifier, $this->userIdentifierHash, $this->createdAt);
+
+        $result = $this->repository->getUser($this->userIdentifierHash)->fetchAssociative();
+
+        $this->assertSame($this->userIdentifier, $result[Store\TableConstants::TABLE_USER_COLUMN_NAME_IDENTIFIER]);
+        $this->assertSame(
+            $this->userIdentifierHash,
+            $result[Store\TableConstants::TABLE_USER_COLUMN_NAME_IDENTIFIER_HASH_SHA256]
+        );
+        $this->assertSame(
+            $this->createdAt->format($this->dateTimeFormat),
+            $result[Store\TableConstants::TABLE_USER_COLUMN_NAME_CREATED_AT]
+        );
+
+        return $result;
+    }
+
+    public function testInsertUserThrowsOnNonUniqueIdentifierHash(): void
+    {
+        $this->expectException(StoreException::class);
+        $this->repository->insertUser($this->userIdentifier, $this->userIdentifierHash, $this->createdAt);
+        $this->repository->insertUser($this->userIdentifier, $this->userIdentifierHash, $this->createdAt);
+    }
+
+    public function testGetUserThrowsOnInvalidDbal(): void
+    {
+        $this->connectionStub->method('dbal')->willThrowException(new \Exception('test'));
+        $repository = new Repository($this->connectionStub, $this->loggerStub);
+        $this->expectException(StoreException::class);
+
+        $repository->getUser($this->userIdentifierHash);
+    }
+
+    /**
+     * @depends testCanInsertAndGetUser
+     */
+    public function testCanInsertAndGetUserVersion(array $userResult): array
+    {
+        $userId = (int)$userResult[Store\TableConstants::TABLE_USER_COLUMN_NAME_ID];
+
+        $this->repository
+            ->insertUserVersion($userId, $this->userAttributes, $this->userAttributesHash, $this->createdAt);
+
+        $result = $this->repository->getUserVersion($userId, $this->userAttributesHash)->fetchAssociative();
+
+        $this->assertSame(
+            $this->userAttributes,
+            $result[Store\TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ATTRIBUTES]
+        );
+        $this->assertSame(
+            $this->userAttributesHash,
+            $result[Store\TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ATTRIBUTES_HASH_SHA256]
+        );
+        $this->assertSame(
+            $this->createdAt->format($this->dateTimeFormat),
+            $result[Store\TableConstants::TABLE_USER_VERSION_COLUMN_NAME_CREATED_AT]
+        );
+
+        return $result;
+    }
+
+    public function testInsertUserVersionThrowsOnNonUniqueAttributesHash(): void
+    {
+        $this->expectException(StoreException::class);
+        $this->repository
+            ->insertUserVersion(1, $this->userAttributes, $this->userAttributesHash, $this->createdAt);
+        $this->repository
+            ->insertUserVersion(1, $this->userAttributes, $this->userAttributesHash, $this->createdAt);
+    }
+
+    public function testGetUserVersionThrowsOnInvalidDbal(): void
+    {
+        $this->connectionStub->method('dbal')->willThrowException(new \Exception('test'));
+        $repository = new Repository($this->connectionStub, $this->loggerStub);
+        $this->expectException(StoreException::class);
+
+        $repository->getUserVersion(1, $this->userIdentifierHash);
+    }
+
+    /**
+     * @depends testCanInsertAndGetIdpVersion
+     * @depends testCanInsertAndGetSpVersion
+     * @depends testCanInsertAndGetUserVersion
+     */
+    public function testCanInsertAndGetIdpSpUserVersion(
+        array $idpVersionResult,
+        array $spVersionResult,
+        array $userVersionResult
+    ): array {
+        $idpVersionId = (int)$idpVersionResult[Store\TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_ID];
+        $spVersionId = (int)$spVersionResult[Store\TableConstants::TABLE_SP_VERSION_COLUMN_NAME_ID];
+        $userVersionId = (int)$userVersionResult[Store\TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ID];
+
+        $this->repository->insertIdpSpUserVersion($idpVersionId, $spVersionId, $userVersionId, $this->createdAt);
+        $result = $this->repository->getIdpSpUserVersion($idpVersionId, $spVersionId, $userVersionId)
+            ->fetchAssociative();
+
+        $this->assertSame(
+            $idpVersionId,
+            (int)$result[Store\TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_IDP_VERSION_ID]
+        );
+        $this->assertSame(
+            $spVersionId,
+            (int)$result[Store\TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_SP_VERSION_ID]
+        );
+        $this->assertSame(
+            $userVersionId,
+            (int)$result[Store\TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_SP_VERSION_ID]
+        );
+        $this->assertSame(
+            $this->createdAt->format($this->dateTimeFormat),
+            $result[Store\TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_CREATED_AT]
+        );
+
+        return $result;
+    }
+
+    public function testInsertIdpSpUserVersionThrowsOnNonUnique(): void
+    {
+        $this->expectException(StoreException::class);
+        $this->repository->insertIdpSpUserVersion(1, 1, 1, $this->createdAt);
+        $this->repository->insertIdpSpUserVersion(1, 1, 1, $this->createdAt);
+    }
+
+    public function testGetIdpSpUserVersionThrowsOnInvalidDbal(): void
+    {
+        $this->connectionStub->method('dbal')->willThrowException(new \Exception('test'));
+        $repository = new Repository($this->connectionStub, $this->loggerStub);
+        $this->expectException(StoreException::class);
+
+        $repository->getIdpSpUserVersion(1, 1, 1);
+    }
+
+    /**
+     * @depends testCanInsertAndGetIdpSpUserVersion
+     */
+    public function testCanInsertAuthenticationEvent(array $idpSpUserVersionResult): void
+    {
+        $idpSpUserVersionId =
+            (int)$idpSpUserVersionResult[Store\TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_ID];
+        $createdAt = $happenedAt = new \DateTimeImmutable();
+
+        $authenticationEventCounterQueryBuilder = $this->connection->dbal()->createQueryBuilder();
+        $authenticationEventCounterQueryBuilder->select('COUNT(id) as authenticationEventCount')
+            ->from(
+                Store\TableConstants::TABLE_PREFIX .
+                $this->connection
+                    ->preparePrefixedTableName(Store\TableConstants::TABLE_NAME_AUTHENTICATION_EVENT)
+            );
+
+        $this->assertSame(0, (int)$authenticationEventCounterQueryBuilder->executeQuery()->fetchOne());
+
+        $this->repository->insertAuthenticationEvent($idpSpUserVersionId, $happenedAt, null, $createdAt);
+
+        $this->assertSame(1, (int)$authenticationEventCounterQueryBuilder->executeQuery()->fetchOne());
+    }
+
+    public function testInsertAuthenticationEventThrowsOnInvalidDbal(): void
+    {
+        $this->connectionStub->method('dbal')->willThrowException(new \Exception('test'));
+        $repository = new Repository($this->connectionStub, $this->loggerStub);
+        $this->expectException(StoreException::class);
+
+        $repository->insertAuthenticationEvent(1, $this->createdAt);
+    }
+
+    public function testCanGetConnectedServiceProviders(): void
+    {
+        $this->repository->insertIdp($this->idpEntityId, $this->idpEntityIdHash, $this->createdAt);
+        $idpResult = $this->repository->getIdp($this->idpEntityIdHash)->fetchAssociative();
+        $idpId = (int)$idpResult[Store\TableConstants::TABLE_IDP_COLUMN_NAME_ID];
+        $this->repository->insertIdpVersion($idpId, $this->idpMetadata, $this->idpMetadataHash, $this->createdAt);
+        $idpVersionResult = $this->repository->getIdpVersion($idpId, $this->idpMetadataHash)->fetchAssociative();
+
+        $this->repository->insertSp($this->spEntityId, $this->spEntityIdHash, $this->createdAt);
+        $spResult = $this->repository->getSp($this->spEntityIdHash)->fetchAssociative();
+        $spId = (int)$spResult[Store\TableConstants::TABLE_SP_COLUMN_NAME_ID];
+        $this->repository->insertSpVersion($spId, $this->spMetadata, $this->spMetadataHash, $this->createdAt);
+        $spVersionResult = $this->repository->getSpVersion($spId, $this->spMetadataHash)->fetchAssociative();
+
+        $this->repository->insertUser($this->userIdentifier, $this->userIdentifierHash, $this->createdAt);
+        $userResult = $this->repository->getUser($this->userIdentifierHash)->fetchAssociative();
+        $userId = (int)$userResult[Store\TableConstants::TABLE_USER_COLUMN_NAME_ID];
+        $this->repository
+            ->insertUserVersion($userId, $this->userAttributes, $this->userAttributesHash, $this->createdAt);
+        $userVersionResult = $this->repository->getUserVersion($userId, $this->userAttributesHash)->fetchAssociative();
+
+        $idpVersionId = (int)$idpVersionResult[Store\TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_ID];
+        $spVersionId = (int)$spVersionResult[Store\TableConstants::TABLE_SP_VERSION_COLUMN_NAME_ID];
+        $userVersionId = (int)$userVersionResult[Store\TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ID];
+
+        $this->repository->insertIdpSpUserVersion($idpVersionId, $spVersionId, $userVersionId, $this->createdAt);
+        $idpSpUserVersionResult = $this->repository->getIdpSpUserVersion($idpVersionId, $spVersionId, $userVersionId)
+            ->fetchAssociative();
+
+        $idpSpUserVersionId =
+            (int)$idpSpUserVersionResult[Store\TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_ID];
+
+        $this->repository->insertAuthenticationEvent(
+            $idpSpUserVersionId,
+            $this->createdAt,
+            $this->clientIpAddress,
+            $this->createdAt
+        );
+
+        $resultArray = $this->repository->getConnectedServiceProviders($this->userIdentifierHash);
+
+        $this->assertCount(1, $resultArray);
+        $this->assertSame(
+            '1',
+            $resultArray[$this->spEntityId]
+            [Store\TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_NUMBER_OF_AUTHENTICATIONS]
+        );
+        $this->assertSame(
+            $this->spMetadata,
+            $resultArray[$this->spEntityId]
+            [Store\TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_SP_METADATA]
+        );
+        $this->assertSame(
+            $this->userAttributes,
+            $resultArray[$this->spEntityId]
+            [Store\TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_USER_ATTRIBUTES]
+        );
+
+        $resultArray = $this->repository->getConnectedServiceProviders($this->userIdentifierHash);
+        $this->assertCount(1, $resultArray);
+
+        $this->repository->insertAuthenticationEvent(
+            $idpSpUserVersionId,
+            $this->createdAt,
+            $this->clientIpAddress,
+            $this->createdAt
+        );
+        $resultArray = $this->repository->getConnectedServiceProviders($this->userIdentifierHash);
+        $this->assertCount(1, $resultArray);
+        $this->assertSame(
+            '2',
+            $resultArray[$this->spEntityId]
+            [Store\TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_NUMBER_OF_AUTHENTICATIONS]
+        );
+        $this->assertSame(
+            $this->spMetadata,
+            $resultArray[$this->spEntityId]
+            [Store\TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_SP_METADATA]
+        );
+        $this->assertSame(
+            $this->userAttributes,
+            $resultArray[$this->spEntityId]
+            [Store\TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_USER_ATTRIBUTES]
+        );
+
+        // Simulate another SP
+        $spEntityIdNew = $this->spEntityId . '-new';
+        $spEntityIdHashNew = $this->spEntityIdHash . '-new';
+        $spMetadataNew = $this->spMetadata . '-new';
+        $spMetadataHashNew = $this->spMetadataHash . '-new';
+        $this->repository->insertSp($spEntityIdNew, $spEntityIdHashNew, $this->createdAt);
+        $spResult = $this->repository->getSp($spEntityIdHashNew)->fetchAssociative();
+        $spId = (int)$spResult[Store\TableConstants::TABLE_SP_COLUMN_NAME_ID];
+        $this->repository->insertSpVersion($spId, $spMetadataNew, $spMetadataHashNew, $this->createdAt);
+        $spVersionResult = $this->repository->getSpVersion($spId, $spMetadataHashNew)->fetchAssociative();
+        $spVersionId = (int)$spVersionResult[Store\TableConstants::TABLE_SP_VERSION_COLUMN_NAME_ID];
+
+        $this->repository->insertIdpSpUserVersion($idpVersionId, $spVersionId, $userVersionId, $this->createdAt);
+        $idpSpUserVersionResult = $this->repository->getIdpSpUserVersion($idpVersionId, $spVersionId, $userVersionId)
+            ->fetchAssociative();
+        $idpSpUserVersionId =
+            (int)$idpSpUserVersionResult[Store\TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_ID];
+
+        $this->repository->insertAuthenticationEvent(
+            $idpSpUserVersionId,
+            $this->createdAt,
+            $this->clientIpAddress,
+            $this->createdAt
+        );
+
+        $resultArray = $this->repository->getConnectedServiceProviders($this->userIdentifierHash);
+        $this->assertCount(2, $resultArray);
+        $this->assertSame(
+            '1',
+            $resultArray[$spEntityIdNew]
+            [Store\TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_NUMBER_OF_AUTHENTICATIONS]
+        );
+        $this->assertSame(
+            $spMetadataNew,
+            $resultArray[$spEntityIdNew]
+            [Store\TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_SP_METADATA]
+        );
+        $this->assertSame(
+            $this->userAttributes,
+            $resultArray[$this->spEntityId]
+            [Store\TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_USER_ATTRIBUTES]
+        );
+
+        // Simulate change in user attributes
+        $userAttributesNew = $this->userAttributes . '-new';
+        $userAttributesHashNew = $this->userAttributesHash . '-new';
+        $this->repository->insertUserVersion($userId, $userAttributesNew, $userAttributesHashNew, $this->createdAt);
+        $userVersionResult = $this->repository->getUserVersion($userId, $userAttributesHashNew)->fetchAssociative();
+        $userVersionId = (int)$userVersionResult[Store\TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ID];
+
+        $this->repository->insertIdpSpUserVersion($idpVersionId, $spVersionId, $userVersionId, $this->createdAt);
+
+        $idpSpUserVersionResult = $this->repository->getIdpSpUserVersion($idpVersionId, $spVersionId, $userVersionId)
+            ->fetchAssociative();
+        $idpSpUserVersionId =
+            (int)$idpSpUserVersionResult[Store\TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_ID];
+
+        $this->repository->insertAuthenticationEvent(
+            $idpSpUserVersionId,
+            $this->createdAt,
+            $this->clientIpAddress,
+            $this->createdAt
+        );
+        $resultArray = $this->repository->getConnectedServiceProviders($this->userIdentifierHash);
+
+        $this->assertCount(2, $resultArray);
+        $this->assertSame(
+            '2',
+            $resultArray[$spEntityIdNew]
+            [Store\TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_NUMBER_OF_AUTHENTICATIONS]
+        );
+        $this->assertSame(
+            $spMetadataNew,
+            $resultArray[$spEntityIdNew]
+            [Store\TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_SP_METADATA]
+        );
+        // New SP with new user attributes version..
+        $this->assertSame(
+            $userAttributesNew,
+            $resultArray[$spEntityIdNew]
+            [Store\TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_USER_ATTRIBUTES]
+        );
+
+        // First SP still has old user attributes version...
+        $this->assertSame(
+            $this->userAttributes,
+            $resultArray[$this->spEntityId]
+            [Store\TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_USER_ATTRIBUTES]
+        );
+    }
+
+    public function testGetConnectedServiceProvidersThrowsOnInvalidDbal(): void
+    {
+        $this->connectionStub->method('dbal')->willThrowException(new \Exception('test'));
+        $repository = new Repository($this->connectionStub, $this->loggerStub);
+        $this->expectException(StoreException::class);
+
+        $repository->getConnectedServiceProviders($this->userIdentifierHash);
+    }
+
+    public function testCanGetActivity(): void
+    {
+        $this->repository->insertIdp($this->idpEntityId, $this->idpEntityIdHash, $this->createdAt);
+        $idpResult = $this->repository->getIdp($this->idpEntityIdHash)->fetchAssociative();
+        $idpId = (int)$idpResult[Store\TableConstants::TABLE_IDP_COLUMN_NAME_ID];
+        $this->repository->insertIdpVersion($idpId, $this->idpMetadata, $this->idpMetadataHash, $this->createdAt);
+        $idpVersionResult = $this->repository->getIdpVersion($idpId, $this->idpMetadataHash)->fetchAssociative();
+
+        $this->repository->insertSp($this->spEntityId, $this->spEntityIdHash, $this->createdAt);
+        $spResult = $this->repository->getSp($this->spEntityIdHash)->fetchAssociative();
+        $spId = (int)$spResult[Store\TableConstants::TABLE_SP_COLUMN_NAME_ID];
+        $this->repository->insertSpVersion($spId, $this->spMetadata, $this->spMetadataHash, $this->createdAt);
+        $spVersionResult = $this->repository->getSpVersion($spId, $this->spMetadataHash)->fetchAssociative();
+
+        $this->repository->insertUser($this->userIdentifier, $this->userIdentifierHash, $this->createdAt);
+        $userResult = $this->repository->getUser($this->userIdentifierHash)->fetchAssociative();
+        $userId = (int)$userResult[Store\TableConstants::TABLE_USER_COLUMN_NAME_ID];
+        $this->repository
+            ->insertUserVersion($userId, $this->userAttributes, $this->userAttributesHash, $this->createdAt);
+        $userVersionResult = $this->repository->getUserVersion($userId, $this->userAttributesHash)->fetchAssociative();
+
+        $idpVersionId = (int)$idpVersionResult[Store\TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_ID];
+        $spVersionId = (int)$spVersionResult[Store\TableConstants::TABLE_SP_VERSION_COLUMN_NAME_ID];
+        $userVersionId = (int)$userVersionResult[Store\TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ID];
+
+        $this->repository->insertIdpSpUserVersion($idpVersionId, $spVersionId, $userVersionId, $this->createdAt);
+        $idpSpUserVersionResult = $this->repository->getIdpSpUserVersion($idpVersionId, $spVersionId, $userVersionId)
+            ->fetchAssociative();
+
+        $idpSpUserVersionId =
+            (int)$idpSpUserVersionResult[Store\TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_ID];
+
+        $this->repository->insertAuthenticationEvent(
+            $idpSpUserVersionId,
+            $this->createdAt,
+            $this->clientIpAddress,
+            $this->createdAt
+        );
+
+        $resultArray = $this->repository->getActivity($this->userIdentifierHash, 10, 0);
+        $this->assertCount(1, $resultArray);
+
+        $this->repository->insertAuthenticationEvent(
+            $idpSpUserVersionId,
+            $this->createdAt,
+            $this->clientIpAddress,
+            $this->createdAt
+        );
+        $resultArray = $this->repository->getActivity($this->userIdentifierHash, 10, 0);
+        $this->assertCount(2, $resultArray);
+
+        $this->repository->insertAuthenticationEvent(
+            $idpSpUserVersionId,
+            $this->createdAt,
+            $this->clientIpAddress,
+            $this->createdAt
+        );
+        $resultArray = $this->repository->getActivity($this->userIdentifierHash, 10, 0);
+        $this->assertCount(3, $resultArray);
+
+        // Simulate another SP
+        $spEntityIdNew = $this->spEntityId . '-new';
+        $spEntityIdHashNew = $this->spEntityIdHash . '-new';
+        $spMetadataNew = $this->spMetadata . '-new';
+        $spMetadataHashNew = $this->spMetadataHash . '-new';
+        $this->repository->insertSp($spEntityIdNew, $spEntityIdHashNew, $this->createdAt);
+        $spResult = $this->repository->getSp($spEntityIdHashNew)->fetchAssociative();
+        $spId = (int)$spResult[Store\TableConstants::TABLE_SP_COLUMN_NAME_ID];
+        $this->repository->insertSpVersion($spId, $spMetadataNew, $spMetadataHashNew, $this->createdAt);
+        $spVersionResult = $this->repository->getSpVersion($spId, $spMetadataHashNew)->fetchAssociative();
+        $spVersionId = (int)$spVersionResult[Store\TableConstants::TABLE_SP_VERSION_COLUMN_NAME_ID];
+
+        $this->repository->insertIdpSpUserVersion($idpVersionId, $spVersionId, $userVersionId, $this->createdAt);
+        $idpSpUserVersionResult = $this->repository->getIdpSpUserVersion($idpVersionId, $spVersionId, $userVersionId)
+            ->fetchAssociative();
+
+        $idpSpUserVersionId =
+            (int)$idpSpUserVersionResult[Store\TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_ID];
+
+        $this->repository->insertAuthenticationEvent(
+            $idpSpUserVersionId,
+            $this->createdAt,
+            $this->clientIpAddress,
+            $this->createdAt
+        );
+        $resultArray = $this->repository->getActivity($this->userIdentifierHash, 10, 0);
+        $this->assertCount(4, $resultArray);
+
+        // Simulate a change in user attributes
+    }
+
+    public function testGetActivityThrowsOnInvalidDbal(): void
+    {
+        $this->connectionStub->method('dbal')->willThrowException(new \Exception('test'));
+        $repository = new Repository($this->connectionStub, $this->loggerStub);
+        $this->expectException(StoreException::class);
+
+        $repository->getActivity($this->userIdentifierHash, 10, 0);
+    }
+
+    public function testCanDeleteAuthenticationEventsOlderThan(): void
+    {
+        $this->repository->insertIdp($this->idpEntityId, $this->idpEntityIdHash, $this->createdAt);
+        $idpResult = $this->repository->getIdp($this->idpEntityIdHash)->fetchAssociative();
+        $idpId = (int)$idpResult[Store\TableConstants::TABLE_IDP_COLUMN_NAME_ID];
+        $this->repository->insertIdpVersion($idpId, $this->idpMetadata, $this->idpMetadataHash, $this->createdAt);
+        $idpVersionResult = $this->repository->getIdpVersion($idpId, $this->idpMetadataHash)->fetchAssociative();
+
+        $this->repository->insertSp($this->spEntityId, $this->spEntityIdHash, $this->createdAt);
+        $spResult = $this->repository->getSp($this->spEntityIdHash)->fetchAssociative();
+        $spId = (int)$spResult[Store\TableConstants::TABLE_SP_COLUMN_NAME_ID];
+        $this->repository->insertSpVersion($spId, $this->spMetadata, $this->spMetadataHash, $this->createdAt);
+        $spVersionResult = $this->repository->getSpVersion($spId, $this->spMetadataHash)->fetchAssociative();
+
+        $this->repository->insertUser($this->userIdentifier, $this->userIdentifierHash, $this->createdAt);
+        $userResult = $this->repository->getUser($this->userIdentifierHash)->fetchAssociative();
+        $userId = (int)$userResult[Store\TableConstants::TABLE_USER_COLUMN_NAME_ID];
+        $this->repository
+            ->insertUserVersion($userId, $this->userAttributes, $this->userAttributesHash, $this->createdAt);
+        $userVersionResult = $this->repository->getUserVersion($userId, $this->userAttributesHash)->fetchAssociative();
+
+        $idpVersionId = (int)$idpVersionResult[Store\TableConstants::TABLE_IDP_VERSION_COLUMN_NAME_ID];
+        $spVersionId = (int)$spVersionResult[Store\TableConstants::TABLE_SP_VERSION_COLUMN_NAME_ID];
+        $userVersionId = (int)$userVersionResult[Store\TableConstants::TABLE_USER_VERSION_COLUMN_NAME_ID];
+
+        $this->repository->insertIdpSpUserVersion($idpVersionId, $spVersionId, $userVersionId, $this->createdAt);
+        $idpSpUserVersionResult = $this->repository->getIdpSpUserVersion($idpVersionId, $spVersionId, $userVersionId)
+            ->fetchAssociative();
+
+        $idpSpUserVersionId =
+            (int)$idpSpUserVersionResult[Store\TableConstants::TABLE_IDP_SP_USER_VERSION_COLUMN_NAME_ID];
+
+        $this->repository->insertAuthenticationEvent(
+            $idpSpUserVersionId,
+            $this->createdAt,
+            $this->clientIpAddress,
+            $this->createdAt
+        );
+
+        $resultArray = $this->repository->getActivity($this->userIdentifierHash, 10, 0);
+        $this->assertCount(1, $resultArray);
+
+        $dateTimeInFuture = $this->createdAt->add(new \DateInterval('P1D'));
+
+        $this->repository->deleteAuthenticationEventsOlderThan($dateTimeInFuture);
+
+        $resultArray = $this->repository->getActivity($this->userIdentifierHash, 10, 0);
+        $this->assertCount(0, $resultArray);
+    }
+
+    public function testDeleteAuthenticationEventsOlderThanThrowsOnInvalidDbal(): void
+    {
+        $this->connectionStub->method('dbal')->willThrowException(new \Exception('test'));
+        $repository = new Repository($this->connectionStub, $this->loggerStub);
+        $this->expectException(StoreException::class);
+
+        $repository->deleteAuthenticationEventsOlderThan(new \DateTimeImmutable());
+    }
+}
diff --git a/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/StoreTest.php b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/StoreTest.php
new file mode 100644
index 0000000..8910b95
--- /dev/null
+++ b/tests/src/Stores/Data/Authentication/DoctrineDbal/Versioned/StoreTest.php
@@ -0,0 +1,683 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned;
+
+use Doctrine\DBAL\Result;
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event;
+use SimpleSAML\Module\accounting\Entities\Authentication\State;
+use SimpleSAML\Module\accounting\Exceptions\StoreException;
+use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Factory;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\TableConstants;
+use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
+use SimpleSAML\Test\Module\accounting\Constants\RawRowResult;
+use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store
+ * @uses   \SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractStore
+ * @uses   \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection
+ * @uses   \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator
+ * @uses   \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Factory
+ * @uses   \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Repository
+ * @uses   \SimpleSAML\Module\accounting\Entities\Authentication\Event
+ * @uses   \SimpleSAML\Module\accounting\Entities\Authentication\State
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\Bases\AbstractMigrator
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000000CreateIdpTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000100CreateIdpVersionTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000200CreateSpTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000300CreateSpVersionTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000400CreateUserTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000500CreateUserVersionTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000600CreateIdpSpUserVersionTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Migrations\Version20220801000700CreateAuthenticationEventTable
+ * @uses \SimpleSAML\Module\accounting\Helpers\FilesystemHelper
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\HashDecoratedState
+ * @uses \SimpleSAML\Module\accounting\Helpers\HashHelper
+ * @uses \SimpleSAML\Module\accounting\Helpers\ArrayHelper
+ * @uses \SimpleSAML\Module\accounting\Helpers\NetworkHelper
+ * @uses \SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider\Bag
+ * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractProvider
+ * @uses \SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider
+ * @uses \SimpleSAML\Module\accounting\Entities\User
+ * @uses \SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractRawEntity
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\RawConnectedServiceProvider
+ * @uses \SimpleSAML\Module\accounting\Entities\Activity\Bag
+ * @uses \SimpleSAML\Module\accounting\Entities\Activity
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\RawActivity
+ * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
+ * @uses \SimpleSAML\Module\accounting\Stores\Bases\AbstractStore
+ *
+ * @psalm-suppress all
+ */
+class StoreTest extends TestCase
+{
+    protected \PHPUnit\Framework\MockObject\Stub $moduleConfigurationStub;
+    protected Migrator $migrator;
+    protected \PHPUnit\Framework\MockObject\Stub $factoryStub;
+    protected Connection $connection;
+    protected State $state;
+    protected Event $authenticationEvent;
+    protected Store\HashDecoratedState $hashDecoratedState;
+    /**
+     * @var \PHPUnit\Framework\MockObject\MockObject|Store\Repository
+     */
+    protected $repositoryMock;
+    /**
+     * @var Result|\PHPUnit\Framework\MockObject\Stub
+     */
+    protected $resultStub;
+    /**
+     * @var \PHPUnit\Framework\MockObject\MockObject|LoggerInterface
+     */
+    protected $loggerMock;
+
+    protected function setUp(): void
+    {
+        $connectionParams = ConnectionParameters::DBAL_SQLITE_MEMORY;
+        $this->moduleConfigurationStub = $this->createStub(ModuleConfiguration::class);
+        $this->moduleConfigurationStub->method('getConnectionParameters')
+            ->willReturn($connectionParams);
+        $this->moduleConfigurationStub->method('getUserIdAttributeName')
+            ->willReturn('hrEduPersonPersistentID');
+
+        $this->connection = new Connection($connectionParams);
+
+        $this->loggerMock = $this->createMock(LoggerInterface::class);
+
+        /** @psalm-suppress InvalidArgument */
+        $this->migrator = new Migrator($this->connection, $this->loggerMock);
+
+        $this->factoryStub = $this->createStub(Factory::class);
+        $this->factoryStub->method('buildConnection')->willReturn($this->connection);
+        $this->factoryStub->method('buildMigrator')->willReturn($this->migrator);
+
+        $this->state = new State(StateArrays::FULL);
+        $this->authenticationEvent = new Event($this->state);
+
+        $this->hashDecoratedState = new Store\HashDecoratedState($this->state);
+        $this->repositoryMock = $this->createMock(Store\Repository::class);
+
+        $this->resultStub = $this->createStub(Result::class);
+    }
+
+    public function testCanConstructInstance(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $this->assertInstanceOf(
+            Store::class,
+            new Store(
+                $this->moduleConfigurationStub,
+                $this->loggerMock,
+                null,
+                ModuleConfiguration\ConnectionType::MASTER,
+                $this->factoryStub
+            )
+        );
+    }
+
+    public function testCanBuildInstance(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $this->assertInstanceOf(
+            Store::class,
+            Store::build($this->moduleConfigurationStub, $this->loggerMock)
+        );
+    }
+
+    public function testCanPersistAuthenticationEvent(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $store = new Store(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub
+        );
+        $store->runSetup();
+
+        $idpCountQueryBuilder = $this->connection->dbal()->createQueryBuilder();
+        $idpVersionCountQueryBuilder = $this->connection->dbal()->createQueryBuilder();
+        $spCountQueryBuilder = $this->connection->dbal()->createQueryBuilder();
+        $spVersionCountQueryBuilder = $this->connection->dbal()->createQueryBuilder();
+        $userCountQueryBuilder = $this->connection->dbal()->createQueryBuilder();
+        $userVersionCountQueryBuilder = $this->connection->dbal()->createQueryBuilder();
+        $idpSpUserVersionCountQueryBuilder = $this->connection->dbal()->createQueryBuilder();
+        $authenticationEventCountQueryBuilder = $this->connection->dbal()->createQueryBuilder();
+
+        $idpCountQueryBuilder->select('COUNT(id) as idpCount')->from(
+            //'vds_idp'
+            $this->connection->preparePrefixedTableName(
+                Store\TableConstants::TABLE_PREFIX . Store\TableConstants::TABLE_NAME_IDP
+            )
+        );
+        $idpVersionCountQueryBuilder->select('COUNT(id) as idpVersionCount')->from(
+            //'vds_idp_version'
+            $this->connection->preparePrefixedTableName(
+                Store\TableConstants::TABLE_PREFIX . Store\TableConstants::TABLE_NAME_IDP_VERSION
+            )
+        );
+        $spCountQueryBuilder->select('COUNT(id) as spCount')->from(
+            //'vds_sp'
+            $this->connection->preparePrefixedTableName(
+                Store\TableConstants::TABLE_PREFIX . Store\TableConstants::TABLE_NAME_SP
+            )
+        );
+        $spVersionCountQueryBuilder->select('COUNT(id) as spVersionCount')->from(
+            //'vds_sp_version'
+            $this->connection->preparePrefixedTableName(
+                Store\TableConstants::TABLE_PREFIX . Store\TableConstants::TABLE_NAME_SP_VERSION
+            )
+        );
+        $userCountQueryBuilder->select('COUNT(id) as userCount')->from(
+            //'vds_user'
+            $this->connection->preparePrefixedTableName(
+                Store\TableConstants::TABLE_PREFIX . Store\TableConstants::TABLE_NAME_USER
+            )
+        );
+        $userVersionCountQueryBuilder->select('COUNT(id) as userVersionCount')->from(
+            //'vds_user_version'
+            $this->connection->preparePrefixedTableName(
+                Store\TableConstants::TABLE_PREFIX . Store\TableConstants::TABLE_NAME_USER_VERSION
+            )
+        );
+        $idpSpUserVersionCountQueryBuilder->select('COUNT(id) as idpSpUserVersionCount')
+            ->from(
+                //'vds_idp_sp_user_version'
+                $this->connection->preparePrefixedTableName(
+                    Store\TableConstants::TABLE_PREFIX . Store\TableConstants::TABLE_NAME_IDP_SP_USER_VERSION
+                )
+            );
+        $authenticationEventCountQueryBuilder->select('COUNT(id) as authenticationEventCount')
+            ->from(
+                //'vds_authentication_event'
+                $this->connection->preparePrefixedTableName(
+                    Store\TableConstants::TABLE_PREFIX . Store\TableConstants::TABLE_NAME_AUTHENTICATION_EVENT
+                )
+            );
+
+        $this->assertSame(0, (int)$idpCountQueryBuilder->executeQuery()->fetchOne());
+        $this->assertSame(0, (int)$idpVersionCountQueryBuilder->executeQuery()->fetchOne());
+        $this->assertSame(0, (int)$spCountQueryBuilder->executeQuery()->fetchOne());
+        $this->assertSame(0, (int)$spVersionCountQueryBuilder->executeQuery()->fetchOne());
+        $this->assertSame(0, (int)$userCountQueryBuilder->executeQuery()->fetchOne());
+        $this->assertSame(0, (int)$userVersionCountQueryBuilder->executeQuery()->fetchOne());
+        $this->assertSame(0, (int)$idpSpUserVersionCountQueryBuilder->executeQuery()->fetchOne());
+        $this->assertSame(0, (int)$authenticationEventCountQueryBuilder->executeQuery()->fetchOne());
+
+        $store->persist($this->authenticationEvent);
+
+        $this->assertSame(1, (int)$idpCountQueryBuilder->executeQuery()->fetchOne());
+        $this->assertSame(1, (int)$idpVersionCountQueryBuilder->executeQuery()->fetchOne());
+        $this->assertSame(1, (int)$spCountQueryBuilder->executeQuery()->fetchOne());
+        $this->assertSame(1, (int)$spVersionCountQueryBuilder->executeQuery()->fetchOne());
+        $this->assertSame(1, (int)$userCountQueryBuilder->executeQuery()->fetchOne());
+        $this->assertSame(1, (int)$userVersionCountQueryBuilder->executeQuery()->fetchOne());
+        $this->assertSame(1, (int)$idpSpUserVersionCountQueryBuilder->executeQuery()->fetchOne());
+        $this->assertSame(1, (int)$authenticationEventCountQueryBuilder->executeQuery()->fetchOne());
+
+        $store->persist($this->authenticationEvent);
+
+        $this->assertSame(1, (int)$idpCountQueryBuilder->executeQuery()->fetchOne());
+        $this->assertSame(1, (int)$idpVersionCountQueryBuilder->executeQuery()->fetchOne());
+        $this->assertSame(1, (int)$spCountQueryBuilder->executeQuery()->fetchOne());
+        $this->assertSame(1, (int)$spVersionCountQueryBuilder->executeQuery()->fetchOne());
+        $this->assertSame(1, (int)$userCountQueryBuilder->executeQuery()->fetchOne());
+        $this->assertSame(1, (int)$userVersionCountQueryBuilder->executeQuery()->fetchOne());
+        $this->assertSame(1, (int)$idpSpUserVersionCountQueryBuilder->executeQuery()->fetchOne());
+        $this->assertSame(2, (int)$authenticationEventCountQueryBuilder->executeQuery()->fetchOne());
+    }
+
+    public function testResolveIdpIdThrowsOnFirstGetIdpFailure(): void
+    {
+        $this->repositoryMock->method('getIdp')->willThrowException(new \Exception('test'));
+        /** @psalm-suppress InvalidArgument */
+        $store = new Store(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub,
+            $this->repositoryMock
+        );
+
+        $this->expectException(StoreException::class);
+
+        $store->persist($this->authenticationEvent);
+    }
+
+    public function testResolveIdpIdThrowsOnInsertAndGetIdpFailure(): void
+    {
+        $this->resultStub->method('fetchOne')->willReturn(false);
+        $this->repositoryMock->method('getIdp')->willReturn($this->resultStub);
+        $this->repositoryMock->method('insertIdp')->willThrowException(new \Exception('test'));
+
+        /** @psalm-suppress InvalidArgument */
+        $store = new Store(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub,
+            $this->repositoryMock
+        );
+
+        $this->expectException(StoreException::class);
+        $this->loggerMock->expects($this->once())->method('warning');
+
+        $store->persist($this->authenticationEvent);
+    }
+
+    public function testResolveIdpVersionIdThrowsOnFirstGetIdpVersionFailure(): void
+    {
+        $this->repositoryMock->method('getIdpVersion')->willThrowException(new \Exception('test'));
+        /** @psalm-suppress InvalidArgument */
+        $store = new Store(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub,
+            $this->repositoryMock
+        );
+
+        $this->expectException(StoreException::class);
+
+        $store->persist($this->authenticationEvent);
+    }
+
+    public function testResolveIdpVersionIdThrowsOnInsertAndGetIdpVersionFailure(): void
+    {
+        $this->resultStub->method('fetchOne')->willReturn(false);
+        $this->repositoryMock->method('getIdpVersion')->willReturn($this->resultStub);
+        $this->repositoryMock->method('insertIdpVersion')->willThrowException(new \Exception('test'));
+
+        /** @psalm-suppress InvalidArgument */
+        $store = new Store(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub,
+            $this->repositoryMock
+        );
+
+        $this->expectException(StoreException::class);
+        $this->loggerMock->expects($this->once())->method('warning');
+
+        $store->persist($this->authenticationEvent);
+    }
+
+    public function testResolveSpIdThrowsOnFirstGetSpFailure(): void
+    {
+        $this->repositoryMock->method('getSp')->willThrowException(new \Exception('test'));
+        /** @psalm-suppress InvalidArgument */
+        $store = new Store(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub,
+            $this->repositoryMock
+        );
+
+        $this->expectException(StoreException::class);
+
+        $store->persist($this->authenticationEvent);
+    }
+
+    public function testResolveSpIdThrowsOnInsertAndGetSpFailure(): void
+    {
+        $this->resultStub->method('fetchOne')->willReturn(false);
+        $this->repositoryMock->method('getSp')->willReturn($this->resultStub);
+        $this->repositoryMock->method('insertSp')->willThrowException(new \Exception('test'));
+
+        /** @psalm-suppress InvalidArgument */
+        $store = new Store(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub,
+            $this->repositoryMock
+        );
+
+        $this->expectException(StoreException::class);
+        $this->loggerMock->expects($this->once())->method('warning');
+
+        $store->persist($this->authenticationEvent);
+    }
+
+    public function testResolveSpVersionIdThrowsOnFirstGetSpVersionFailure(): void
+    {
+        $this->repositoryMock->method('getSpVersion')->willThrowException(new \Exception('test'));
+        /** @psalm-suppress InvalidArgument */
+        $store = new Store(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub,
+            $this->repositoryMock
+        );
+
+        $this->expectException(StoreException::class);
+
+        $store->persist($this->authenticationEvent);
+    }
+
+    public function testResolveSpVersionIdThrowsOnInsertAndGetSpVersionFailure(): void
+    {
+        $this->resultStub->method('fetchOne')->willReturn(false);
+        $this->repositoryMock->method('getSpVersion')->willReturn($this->resultStub);
+        $this->repositoryMock->method('insertSpVersion')->willThrowException(new \Exception('test'));
+
+        /** @psalm-suppress InvalidArgument */
+        $store = new Store(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub,
+            $this->repositoryMock
+        );
+
+        $this->expectException(StoreException::class);
+        $this->loggerMock->expects($this->once())->method('warning');
+
+        $store->persist($this->authenticationEvent);
+    }
+
+    public function testResolveUserIdThrowsOnInvalidUserIdentifierValue(): void
+    {
+        $moduleConfigurationStub = $this->createStub(ModuleConfiguration::class);
+        $moduleConfigurationStub->method('getUserIdAttributeName')->willReturn('invalid');
+
+        /** @psalm-suppress InvalidArgument */
+        $store = new Store(
+            $moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub,
+            $this->repositoryMock
+        );
+
+        $this->expectException(UnexpectedValueException::class);
+
+        $store->persist($this->authenticationEvent);
+    }
+
+    public function testResolveUserIdThrowsOnFirstGetUserFailure(): void
+    {
+        $this->repositoryMock->method('getUser')->willThrowException(new \Exception('test'));
+        /** @psalm-suppress InvalidArgument */
+        $store = new Store(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub,
+            $this->repositoryMock
+        );
+
+        $this->expectException(StoreException::class);
+
+        $store->persist($this->authenticationEvent);
+    }
+
+    public function testResolveUserIdThrowsOnInsertAndGetUserFailure(): void
+    {
+        $this->resultStub->method('fetchOne')->willReturn(false);
+        $this->repositoryMock->method('getUser')->willReturn($this->resultStub);
+        $this->repositoryMock->method('insertUser')->willThrowException(new \Exception('test'));
+
+        /** @psalm-suppress InvalidArgument */
+        $store = new Store(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub,
+            $this->repositoryMock
+        );
+
+        $this->expectException(StoreException::class);
+        $this->loggerMock->expects($this->once())->method('warning');
+
+        $store->persist($this->authenticationEvent);
+    }
+
+    public function testResolveUserVersionIdThrowsOnFirstGetUserVersionFailure(): void
+    {
+        $this->repositoryMock->method('getUserVersion')->willThrowException(new \Exception('test'));
+        /** @psalm-suppress InvalidArgument */
+        $store = new Store(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub,
+            $this->repositoryMock
+        );
+
+        $this->expectException(StoreException::class);
+
+        $store->persist($this->authenticationEvent);
+    }
+
+    public function testResolveUserVersionIdThrowsOnInsertAndGetUserVersionFailure(): void
+    {
+        $this->resultStub->method('fetchOne')->willReturn(false);
+        $this->repositoryMock->method('getUserVersion')->willReturn($this->resultStub);
+        $this->repositoryMock->method('insertUserVersion')->willThrowException(new \Exception('test'));
+
+        /** @psalm-suppress InvalidArgument */
+        $store = new Store(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub,
+            $this->repositoryMock
+        );
+
+        $this->expectException(StoreException::class);
+        $this->loggerMock->expects($this->once())->method('warning');
+
+        $store->persist($this->authenticationEvent);
+    }
+
+    public function testResolveIdpSpUserVersionIdThrowsOnFirstGetIdpSpUserVersionFailure(): void
+    {
+        $this->repositoryMock->method('getIdpSpUserVersion')->willThrowException(new \Exception('test'));
+        /** @psalm-suppress InvalidArgument */
+        $store = new Store(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub,
+            $this->repositoryMock
+        );
+
+        $this->expectException(StoreException::class);
+
+        $store->persist($this->authenticationEvent);
+    }
+
+    public function testResolveIdpSpUserVersionIdThrowsOnInsertAndGetIdpSpUserVersionFailure(): void
+    {
+        $this->resultStub->method('fetchOne')->willReturn(false);
+        $this->repositoryMock->method('getIdpSpUserVersion')->willReturn($this->resultStub);
+        $this->repositoryMock->method('insertIdpSpUserVersion')->willThrowException(new \Exception('test'));
+
+        /** @psalm-suppress InvalidArgument */
+        $store = new Store(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub,
+            $this->repositoryMock
+        );
+
+        $this->expectException(StoreException::class);
+        $this->loggerMock->expects($this->once())->method('warning');
+
+        $store->persist($this->authenticationEvent);
+    }
+
+    public function testGetConnectedOrganizationsReturnsEmptyBagIfNoResults(): void
+    {
+        $this->repositoryMock->method('getConnectedServiceProviders')->willReturn([]);
+
+        /** @psalm-suppress InvalidArgument */
+        $store = new Store(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub,
+            $this->repositoryMock
+        );
+
+        $connectedServiceProviderBag = $store->getConnectedOrganizations('test');
+
+        $this->assertEmpty($connectedServiceProviderBag->getAll());
+    }
+
+    public function testCanGetConnectedOrganizationsBag(): void
+    {
+        $this->repositoryMock->method('getConnectedServiceProviders')
+            ->willReturn([RawRowResult::CONNECTED_ORGANIZATION]);
+
+        /** @psalm-suppress InvalidArgument */
+        $store = new Store(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub,
+            $this->repositoryMock
+        );
+
+        $connectedServiceProviderBag = $store->getConnectedOrganizations('test');
+
+        $this->assertNotEmpty($connectedServiceProviderBag->getAll());
+    }
+
+    public function testGetConnectedOrganizationsThrowsForInvalidResult(): void
+    {
+        $rawResult = RawRowResult::CONNECTED_ORGANIZATION;
+        unset($rawResult[TableConstants::ENTITY_CONNECTED_ORGANIZATION_COLUMN_NAME_NUMBER_OF_AUTHENTICATIONS]);
+
+        $this->repositoryMock->method('getConnectedServiceProviders')
+            ->willReturn([$rawResult]);
+
+        /** @psalm-suppress InvalidArgument */
+        $store = new Store(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub,
+            $this->repositoryMock
+        );
+
+        $this->expectException(StoreException::class);
+        $store->getConnectedOrganizations('test');
+    }
+
+    public function testGetActivityReturnsEmptyBagIfNoResults(): void
+    {
+        $this->repositoryMock->method('getActivity')->willReturn([]);
+
+        /** @psalm-suppress InvalidArgument */
+        $store = new Store(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub,
+            $this->repositoryMock
+        );
+
+        $activityBag = $store->getActivity('test', 10, 0);
+
+        $this->assertEmpty($activityBag->getAll());
+    }
+
+    public function testCanGetActivityBag(): void
+    {
+        $this->repositoryMock->method('getActivity')
+            ->willReturn([RawRowResult::ACTIVITY]);
+
+        /** @psalm-suppress InvalidArgument */
+        $store = new Store(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub,
+            $this->repositoryMock
+        );
+
+        $activityBag = $store->getActivity('test', 10, 0);
+
+        $this->assertNotEmpty($activityBag->getAll());
+    }
+
+    public function testGetActivityThrowsForInvalidResult(): void
+    {
+        $rawResult = RawRowResult::ACTIVITY;
+        unset($rawResult[TableConstants::ENTITY_ACTIVITY_COLUMN_NAME_HAPPENED_AT]);
+
+        $this->repositoryMock->method('getActivity')
+            ->willReturn([$rawResult]);
+
+        /** @psalm-suppress InvalidArgument */
+        $store = new Store(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub,
+            $this->repositoryMock
+        );
+
+        $this->expectException(StoreException::class);
+        $store->getActivity('test', 10, 0);
+    }
+
+    public function testCanDeleteDataOlderThan(): void
+    {
+        $dateTime = new \DateTimeImmutable();
+
+        $this->repositoryMock->expects($this->once())
+            ->method('deleteAuthenticationEventsOlderThan')
+            ->with($dateTime);
+
+        /** @psalm-suppress InvalidArgument */
+        $store = new Store(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub,
+            $this->repositoryMock
+        );
+
+        $store->deleteDataOlderThan($dateTime);
+    }
+}
diff --git a/tests/src/Stores/Jobs/DoctrineDbal/Store/Migrations/Version20220601000000CreateJobTableTest.php b/tests/src/Stores/Jobs/DoctrineDbal/Store/Migrations/Version20220601000000CreateJobTableTest.php
new file mode 100644
index 0000000..b56de0e
--- /dev/null
+++ b/tests/src/Stores/Jobs/DoctrineDbal/Store/Migrations/Version20220601000000CreateJobTableTest.php
@@ -0,0 +1,73 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations;
+
+use Doctrine\DBAL\Schema\AbstractSchemaManager;
+use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection;
+use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store;
+use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Version20220601000000CreateJobTable;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Version20220601000000CreateJobTable
+ * @covers \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Bases\AbstractCreateJobsTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration
+ */
+class Version20220601000000CreateJobTableTest extends TestCase
+{
+    protected Connection $connection;
+    protected \Doctrine\DBAL\Schema\AbstractSchemaManager $schemaManager;
+    protected string $tableName;
+
+    protected function setUp(): void
+    {
+        $this->connection = new Connection(ConnectionParameters::DBAL_SQLITE_MEMORY);
+        $this->schemaManager = $this->connection->dbal()->createSchemaManager();
+        $this->tableName = $this->connection->preparePrefixedTableName(Store\TableConstants::TABLE_NAME_JOB);
+    }
+
+    public function testCanRunMigration(): void
+    {
+        $this->assertFalse($this->schemaManager->tablesExist($this->tableName));
+        $migration = new Version20220601000000CreateJobTable($this->connection);
+        $migration->run();
+        $this->assertTrue($this->schemaManager->tablesExist($this->tableName));
+        $migration->revert();
+        $this->assertFalse($this->schemaManager->tablesExist($this->tableName));
+    }
+
+    public function testRunThrowsMigrationException(): void
+    {
+        $connectionStub = $this->createStub(Connection::class);
+        $dbalStub = $this->createStub(\Doctrine\DBAL\Connection::class);
+        $schemaManagerStub = $this->createStub(AbstractSchemaManager::class);
+
+        $connectionStub->method('dbal')->willReturn($dbalStub);
+        $dbalStub->method('createSchemaManager')->willReturn($schemaManagerStub);
+        $schemaManagerStub->method('createTable')
+            ->willThrowException(new \Doctrine\DBAL\Exception('test'));
+
+        $migration = new Version20220601000000CreateJobTable($connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->run();
+    }
+
+    public function testRevertThrowsMigrationException(): void
+    {
+        $connectionStub = $this->createStub(Connection::class);
+        $dbalStub = $this->createStub(\Doctrine\DBAL\Connection::class);
+        $schemaManagerStub = $this->createStub(AbstractSchemaManager::class);
+
+        $connectionStub->method('dbal')->willReturn($dbalStub);
+        $dbalStub->method('createSchemaManager')->willReturn($schemaManagerStub);
+        $schemaManagerStub->method('dropTable')
+            ->willThrowException(new \Doctrine\DBAL\Exception('test'));
+
+        $migration = new Version20220601000000CreateJobTable($connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->revert();
+    }
+}
diff --git a/tests/src/Stores/Jobs/DoctrineDbal/Store/Migrations/Version20220601000100CreateJobFailedTableTest.php b/tests/src/Stores/Jobs/DoctrineDbal/Store/Migrations/Version20220601000100CreateJobFailedTableTest.php
new file mode 100644
index 0000000..0240fc6
--- /dev/null
+++ b/tests/src/Stores/Jobs/DoctrineDbal/Store/Migrations/Version20220601000100CreateJobFailedTableTest.php
@@ -0,0 +1,73 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations;
+
+use Doctrine\DBAL\Schema\AbstractSchemaManager;
+use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection;
+use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store;
+use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Version20220601000100CreateJobFailedTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration
+ * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Bases\AbstractCreateJobsTable
+ */
+class Version20220601000100CreateJobFailedTableTest extends TestCase
+{
+    protected Connection $connection;
+    protected \Doctrine\DBAL\Schema\AbstractSchemaManager $schemaManager;
+    protected string $tableName;
+
+    protected function setUp(): void
+    {
+        $this->connection = new Connection(ConnectionParameters::DBAL_SQLITE_MEMORY);
+        $this->schemaManager = $this->connection->dbal()->createSchemaManager();
+        $this->tableName = $this->connection->preparePrefixedTableName(Store\TableConstants::TABLE_NAME_JOB_FAILED);
+    }
+
+    public function testCanRunMigration(): void
+    {
+        $this->assertFalse($this->schemaManager->tablesExist($this->tableName));
+        $migration = new Migrations\Version20220601000100CreateJobFailedTable($this->connection);
+        $migration->run();
+        $this->assertTrue($this->schemaManager->tablesExist($this->tableName));
+        $migration->revert();
+        $this->assertFalse($this->schemaManager->tablesExist($this->tableName));
+    }
+
+    public function testRunThrowsMigrationException(): void
+    {
+        $connectionStub = $this->createStub(Connection::class);
+        $dbalStub = $this->createStub(\Doctrine\DBAL\Connection::class);
+        $schemaManagerStub = $this->createStub(AbstractSchemaManager::class);
+
+        $connectionStub->method('dbal')->willReturn($dbalStub);
+        $dbalStub->method('createSchemaManager')->willReturn($schemaManagerStub);
+        $schemaManagerStub->method('createTable')
+            ->willThrowException(new \Doctrine\DBAL\Exception('test'));
+
+        $migration = new Migrations\Version20220601000100CreateJobFailedTable($connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->run();
+    }
+
+    public function testRevertThrowsMigrationException(): void
+    {
+        $connectionStub = $this->createStub(Connection::class);
+        $dbalStub = $this->createStub(\Doctrine\DBAL\Connection::class);
+        $schemaManagerStub = $this->createStub(AbstractSchemaManager::class);
+
+        $connectionStub->method('dbal')->willReturn($dbalStub);
+        $dbalStub->method('createSchemaManager')->willReturn($schemaManagerStub);
+        $schemaManagerStub->method('dropTable')
+            ->willThrowException(new \Doctrine\DBAL\Exception('test'));
+
+        $migration = new Migrations\Version20220601000100CreateJobFailedTable($connectionStub);
+        $this->expectException(MigrationException::class);
+        $migration->revert();
+    }
+}
diff --git a/tests/src/Stores/Jobs/DoctrineDbal/Store/RawJobTest.php b/tests/src/Stores/Jobs/DoctrineDbal/Store/RawJobTest.php
new file mode 100644
index 0000000..fa92aa6
--- /dev/null
+++ b/tests/src/Stores/Jobs/DoctrineDbal/Store/RawJobTest.php
@@ -0,0 +1,127 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Jobs\DoctrineDbal\Store;
+
+use Doctrine\DBAL\Platforms\AbstractPlatform;
+use Doctrine\DBAL\Platforms\SqlitePlatform;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event;
+use SimpleSAML\Module\accounting\Entities\Authentication\State;
+use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException;
+use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store;
+use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\RawJob;
+use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\RawJob
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Event
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\State
+ * @uses \SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractRawEntity
+ * @uses \SimpleSAML\Module\accounting\Helpers\NetworkHelper
+ * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
+ */
+class RawJobTest extends TestCase
+{
+    protected Event $authenticationEvent;
+    protected array $validRawRow;
+    protected \PHPUnit\Framework\MockObject\Stub $abstractPlatformStub;
+
+    protected function setUp(): void
+    {
+        $this->abstractPlatformStub = $this->createStub(AbstractPlatform::class);
+        $this->authenticationEvent = new Event(new State(StateArrays::FULL));
+        $this->validRawRow = [
+            Store\TableConstants::COLUMN_NAME_ID => 1,
+            Store\TableConstants::COLUMN_NAME_PAYLOAD => serialize($this->authenticationEvent),
+            Store\TableConstants::COLUMN_NAME_TYPE => get_class($this->authenticationEvent),
+            Store\TableConstants::COLUMN_NAME_CREATED_AT => '2022-08-17 13:26:12',
+        ];
+    }
+
+    public function testCanInstantiateValidRawJob(): void
+    {
+        $abstractPlatform = new SqlitePlatform();
+        $rawJob = new Store\RawJob($this->validRawRow, $abstractPlatform);
+        $this->assertSame($rawJob->getId(), $this->validRawRow[Store\TableConstants::COLUMN_NAME_ID]);
+        $this->assertEquals($rawJob->getPayload(), $this->authenticationEvent);
+        $this->assertSame($rawJob->getType(), $this->validRawRow[Store\TableConstants::COLUMN_NAME_TYPE]);
+        $this->assertInstanceOf(\DateTimeImmutable::class, $rawJob->getCreatedAt());
+    }
+
+    public function testThrowsOnEmptyColumn(): void
+    {
+        $invalidRawRow = $this->validRawRow;
+        unset($invalidRawRow[Store\TableConstants::COLUMN_NAME_ID]);
+
+        $this->expectException(UnexpectedValueException::class);
+
+        /** @psalm-suppress InvalidArgument */
+        new RawJob($invalidRawRow, $this->abstractPlatformStub);
+    }
+
+    public function testThrowsOnNonNumericId(): void
+    {
+        $invalidRawRow = $this->validRawRow;
+        $invalidRawRow[Store\TableConstants::COLUMN_NAME_ID] = 'a';
+
+        $this->expectException(UnexpectedValueException::class);
+
+        /** @psalm-suppress InvalidArgument */
+        new RawJob($invalidRawRow, $this->abstractPlatformStub);
+    }
+
+    public function testThrowsOnNonStringPayload(): void
+    {
+        $invalidRawRow = $this->validRawRow;
+        $invalidRawRow[Store\TableConstants::COLUMN_NAME_PAYLOAD] = 123;
+
+        $this->expectException(UnexpectedValueException::class);
+
+        /** @psalm-suppress InvalidArgument */
+        new RawJob($invalidRawRow, $this->abstractPlatformStub);
+    }
+
+    public function testThrowsOnNonAbstractPayload(): void
+    {
+        $invalidRawRow = $this->validRawRow;
+        $invalidRawRow[Store\TableConstants::COLUMN_NAME_PAYLOAD] = serialize('abc');
+
+        $this->expectException(UnexpectedValueException::class);
+
+        /** @psalm-suppress InvalidArgument */
+        new Store\RawJob($invalidRawRow, $this->abstractPlatformStub);
+    }
+
+    public function testThrowsOnNonStringType(): void
+    {
+        $invalidRawRow = $this->validRawRow;
+        $invalidRawRow[Store\TableConstants::COLUMN_NAME_TYPE] = 123;
+
+        $this->expectException(UnexpectedValueException::class);
+
+        /** @psalm-suppress InvalidArgument */
+        new Store\RawJob($invalidRawRow, $this->abstractPlatformStub);
+    }
+
+    public function testThrowsOnNonStringCreatedAt(): void
+    {
+        $invalidRawRow = $this->validRawRow;
+        $invalidRawRow[Store\TableConstants::COLUMN_NAME_CREATED_AT] = 123;
+
+        $this->expectException(UnexpectedValueException::class);
+
+        /** @psalm-suppress InvalidArgument */
+        new RawJob($invalidRawRow, $this->abstractPlatformStub);
+    }
+
+    public function testThrowsOnNonValidCreatedAt(): void
+    {
+        $invalidRawRow = $this->validRawRow;
+        $invalidRawRow[Store\TableConstants::COLUMN_NAME_CREATED_AT] = '123';
+
+        $this->expectException(UnexpectedValueException::class);
+
+        /** @psalm-suppress InvalidArgument */
+        new Store\RawJob($invalidRawRow, $this->abstractPlatformStub);
+    }
+}
diff --git a/tests/src/Stores/Jobs/DoctrineDbal/Store/RepositoryTest.php b/tests/src/Stores/Jobs/DoctrineDbal/Store/RepositoryTest.php
new file mode 100644
index 0000000..3241e83
--- /dev/null
+++ b/tests/src/Stores/Jobs/DoctrineDbal/Store/RepositoryTest.php
@@ -0,0 +1,233 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Jobs\DoctrineDbal\Store;
+
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event;
+use SimpleSAML\Module\accounting\Entities\Authentication\State;
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractJob;
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload;
+use SimpleSAML\Module\accounting\Entities\GenericJob;
+use SimpleSAML\Module\accounting\Exceptions\StoreException;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Services\Logger;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Factory;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator;
+use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store;
+use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Repository;
+use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
+use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Repository
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection
+ * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractJob
+ * @uses \SimpleSAML\Module\accounting\Helpers\FilesystemHelper
+ * @uses \SimpleSAML\Module\accounting\ModuleConfiguration
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\Bases\AbstractMigrator
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator
+ * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store
+ * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Version20220601000000CreateJobTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Version20220601000100CreateJobFailedTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\RawJob
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Event
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Event\Job
+ * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Bases\AbstractCreateJobsTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractStore
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\State
+ * @uses \SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractRawEntity
+ * @uses \SimpleSAML\Module\accounting\Helpers\NetworkHelper
+ * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
+ * @uses \SimpleSAML\Module\accounting\Stores\Bases\AbstractStore
+ */
+class RepositoryTest extends TestCase
+{
+    protected ModuleConfiguration $moduleConfiguration;
+    protected Connection $connection;
+    protected \PHPUnit\Framework\MockObject\Stub $loggerServiceStub;
+    protected Migrator $migrator;
+    protected \PHPUnit\Framework\MockObject\Stub $factoryStub;
+    protected \PHPUnit\Framework\MockObject\Stub $payloadStub;
+    protected \PHPUnit\Framework\MockObject\Stub $jobStub;
+    protected Store $jobsStore;
+    protected string $jobsTableName;
+
+    protected function setUp(): void
+    {
+        // Configuration directory is set by phpunit using php ENV setting feature (check phpunit.xml).
+        $this->moduleConfiguration = new ModuleConfiguration('module_accounting.php');
+        $this->connection = new Connection(ConnectionParameters::DBAL_SQLITE_MEMORY);
+
+        $this->loggerServiceStub = $this->createStub(Logger::class);
+
+        /** @psalm-suppress InvalidArgument */
+        $this->migrator = new Migrator($this->connection, $this->loggerServiceStub);
+
+        $this->factoryStub = $this->createStub(Factory::class);
+        $this->factoryStub->method('buildConnection')->willReturn($this->connection);
+        $this->factoryStub->method('buildMigrator')->willReturn($this->migrator);
+
+        $this->payloadStub = $this->createStub(AbstractPayload::class);
+        $this->jobStub = $this->createStub(GenericJob::class);
+        $this->jobStub->method('getPayload')->willReturn($this->payloadStub);
+        $this->jobStub->method('getType')->willReturn(GenericJob::class);
+        $this->jobStub->method('getCreatedAt')->willReturn(new \DateTimeImmutable());
+
+        /** @psalm-suppress InvalidArgument */
+        $this->jobsStore = new Store(
+            $this->moduleConfiguration,
+            $this->loggerServiceStub,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub
+        );
+
+        $this->jobsTableName = $this->connection->preparePrefixedTableName(Store\TableConstants::TABLE_NAME_JOB);
+    }
+
+    public function testCanInsertAndGetJob(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $repository = new Repository($this->connection, $this->jobsTableName, $this->loggerServiceStub);
+        // Running setup will ensure that all migrations are ran.
+        $this->jobsStore->runSetup();
+
+        $this->assertNull($repository->getNext());
+
+        /** @psalm-suppress InvalidArgument */
+        $repository->insert($this->jobStub);
+
+        $this->assertNotNull($repository->getNext());
+    }
+
+    public function testInsertThrowsIfJobsStoreSetupNotRan(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $repository = new Repository($this->connection, $this->jobsTableName, $this->loggerServiceStub);
+        // Running setup will ensure that all migrations are ran.
+        //$this->jobsStore->runSetup();
+
+        $this->expectException(StoreException::class);
+
+        /** @psalm-suppress InvalidArgument */
+        $repository->insert($this->jobStub);
+    }
+
+    public function testInsertThrowsForInvalidJobType(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $repository = new Repository($this->connection, $this->jobsTableName, $this->loggerServiceStub);
+        // Running setup will ensure that all migrations are ran.
+        $this->jobsStore->runSetup();
+
+        $this->expectException(StoreException::class);
+
+        $invalidType = str_pad('abc', Store\TableConstants::COLUMN_TYPE_LENGTH + 1);
+        $jobStub = $this->createStub(GenericJob::class);
+        $jobStub->method('getPayload')->willReturn($this->payloadStub);
+        $jobStub->method('getType')->willReturn($invalidType);
+        $jobStub->method('getCreatedAt')->willReturn(new \DateTimeImmutable());
+
+        /** @psalm-suppress InvalidArgument */
+        $repository->insert($jobStub);
+    }
+
+    public function testGetNextThrowsIfJobsStoreSetupNotRan(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $repository = new Repository($this->connection, $this->jobsTableName, $this->loggerServiceStub);
+        // Running setup will ensure that all migrations are ran.
+        //$this->jobsStore->runSetup();
+
+        $this->expectException(StoreException::class);
+
+        $repository->getNext();
+    }
+
+    public function testGetNextThrowsForInvalidJobType(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $repository = new Repository($this->connection, $this->jobsTableName, $this->loggerServiceStub);
+        // Running setup will ensure that all migrations are ran.
+        $this->jobsStore->runSetup();
+
+        $payloadStub = $this->createStub(AbstractPayload::class);
+        $jobStub = $this->createStub(AbstractJob::class); // Abstract classes can't be initialized..
+        $jobStub->method('getPayload')->willReturn($payloadStub);
+        $jobStub->method('getType')->willReturn(AbstractJob::class);
+        $jobStub->method('getCreatedAt')->willReturn(new \DateTimeImmutable());
+
+        /** @psalm-suppress InvalidArgument */
+        $repository->insert($jobStub);
+
+        $this->expectException(StoreException::class);
+
+        $repository->getNext();
+    }
+
+    public function testCanDeleteJob(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $repository = new Repository($this->connection, $this->jobsTableName, $this->loggerServiceStub);
+        // Running setup will ensure that all migrations are ran.
+        $this->jobsStore->runSetup();
+
+        $this->assertFalse($repository->delete(1));
+        /** @psalm-suppress InvalidArgument */
+        $repository->insert($this->jobStub);
+        $job = $repository->getNext();
+        if ($job === null) {
+            throw new \Exception('Invalid job.');
+        }
+        $jobId = $job->getId();
+        if ($jobId === null) {
+            throw new \Exception('Invalid job ID.');
+        }
+        $this->assertTrue($repository->delete($jobId));
+        $this->assertFalse($repository->delete($jobId));
+    }
+
+    public function testDeleteThrowsWhenJobsStoreSetupNotRan(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $repository = new Repository($this->connection, $this->jobsTableName, $this->loggerServiceStub);
+        // Running setup will ensure that all migrations are ran.
+        //$this->jobsStore->runSetup();
+
+        $this->expectException(StoreException::class);
+
+        $repository->delete(1);
+    }
+
+    public function testCanGetSpecificJobType(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $repository = new Repository($this->connection, $this->jobsTableName, $this->loggerServiceStub);
+        // Running setup will ensure that all migrations are ran.
+        $this->jobsStore->runSetup();
+
+        $this->assertNull($repository->getNext());
+
+        /** @psalm-suppress InvalidArgument */
+        $repository->insert($this->jobStub);
+
+        $authenticationEvent = new Event(new State(StateArrays::FULL));
+        $authenticationEventJob = new Event\Job($authenticationEvent);
+
+        $repository->insert($authenticationEventJob);
+
+        $this->assertInstanceOf(Event\Job::class, $repository->getNext(Event\Job::class));
+    }
+
+    public function testInitializationThrowsForInvalidJobsTableName(): void
+    {
+        $this->expectException(StoreException::class);
+
+        /** @psalm-suppress InvalidArgument */
+        new Repository($this->connection, 'invalid-table-name', $this->loggerServiceStub);
+    }
+}
diff --git a/tests/src/Stores/Jobs/DoctrineDbal/StoreTest.php b/tests/src/Stores/Jobs/DoctrineDbal/StoreTest.php
new file mode 100644
index 0000000..3aca118
--- /dev/null
+++ b/tests/src/Stores/Jobs/DoctrineDbal/StoreTest.php
@@ -0,0 +1,388 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Jobs\DoctrineDbal;
+
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event;
+use SimpleSAML\Module\accounting\Entities\Authentication\State;
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractJob;
+use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload;
+use SimpleSAML\Module\accounting\Entities\GenericJob;
+use SimpleSAML\Module\accounting\Exceptions\StoreException;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Services\Logger;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Factory;
+use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator;
+use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store;
+use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
+use SimpleSAML\Test\Module\accounting\Constants\StateArrays;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store
+ * @covers \SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractStore
+ * @uses \SimpleSAML\Module\accounting\ModuleConfiguration
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Factory
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\Bases\AbstractMigrator
+ * @uses \SimpleSAML\Module\accounting\Helpers\FilesystemHelper
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration
+ * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Version20220601000000CreateJobTable
+ * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Version20220601000100CreateJobFailedTable
+ * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractJob
+ * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\RawJob
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Event
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\Event\Job
+ * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Repository
+ * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\Store\Migrations\Bases\AbstractCreateJobsTable
+ * @uses \SimpleSAML\Module\accounting\Entities\Authentication\State
+ * @uses \SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractRawEntity
+ * @uses \SimpleSAML\Module\accounting\Helpers\NetworkHelper
+ * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
+ * @uses \SimpleSAML\Module\accounting\Stores\Bases\AbstractStore
+ */
+class StoreTest extends TestCase
+{
+    protected ModuleConfiguration $moduleConfiguration;
+    protected \PHPUnit\Framework\MockObject\Stub $factoryStub;
+    protected Connection $connection;
+    protected \PHPUnit\Framework\MockObject\Stub $loggerStub;
+    protected Migrator $migrator;
+    protected \PHPUnit\Framework\MockObject\Stub $payloadStub;
+    protected \PHPUnit\Framework\MockObject\Stub $jobStub;
+
+    protected function setUp(): void
+    {
+        // Configuration directory is set by phpunit using php ENV setting feature (check phpunit.xml).
+        $this->moduleConfiguration = new ModuleConfiguration('module_accounting.php');
+        $this->connection = new Connection(ConnectionParameters::DBAL_SQLITE_MEMORY);
+
+        $this->loggerStub = $this->createStub(Logger::class);
+
+        /** @psalm-suppress InvalidArgument */
+        $this->migrator = new Migrator($this->connection, $this->loggerStub);
+
+        $this->factoryStub = $this->createStub(Factory::class);
+        $this->factoryStub->method('buildConnection')->willReturn($this->connection);
+        $this->factoryStub->method('buildMigrator')->willReturn($this->migrator);
+
+        $this->payloadStub = $this->createStub(AbstractPayload::class);
+        $this->jobStub = $this->createStub(GenericJob::class);
+        $this->jobStub->method('getPayload')->willReturn($this->payloadStub);
+        $this->jobStub->method('getType')->willReturn(GenericJob::class);
+        $this->jobStub->method('getCreatedAt')->willReturn(new \DateTimeImmutable());
+        $this->jobStub->method('getId')->willReturn(1);
+    }
+
+    public function testSetupDependsOnMigratorSetup(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $jobsStore = new Store(
+            $this->moduleConfiguration,
+            $this->loggerStub,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub
+        );
+
+        $this->assertTrue($this->migrator->needsSetup());
+        $this->assertTrue($jobsStore->needsSetup());
+
+        $jobsStore->runSetup();
+
+        $this->assertFalse($jobsStore->needsSetup());
+        $this->assertFalse($this->migrator->needsSetup());
+    }
+
+    public function testSetupDependsOnMigrations(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $jobsStore = new Store(
+            $this->moduleConfiguration,
+            $this->loggerStub,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub
+        );
+
+        // Run migrator setup beforehand, so it only depends on Store migrations setup
+        $this->migrator->runSetup();
+        $this->assertTrue($jobsStore->needsSetup());
+
+        $jobsStore->runSetup();
+
+        $this->assertFalse($jobsStore->needsSetup());
+    }
+
+    public function testCanGetPrefixedTableNames(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $jobsStore = new Store(
+            $this->moduleConfiguration,
+            $this->loggerStub,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub
+        );
+
+        $tableNameJobs = $this->connection->preparePrefixedTableName(Store\TableConstants::TABLE_NAME_JOB);
+        $tableNameFailedJobs = $this->connection->preparePrefixedTableName(
+            Store\TableConstants::TABLE_NAME_JOB_FAILED
+        );
+
+        $this->assertSame($tableNameJobs, $jobsStore->getPrefixedTableNameJobs());
+        $this->assertSame($tableNameFailedJobs, $jobsStore->getPrefixedTableNameFailedJobs());
+    }
+
+    public function testCanBuildInstanceStatically(): void
+    {
+        $moduleConfiguration = $this->createStub(ModuleConfiguration::class);
+        $moduleConfiguration->method('getConnectionParameters')
+            ->willReturn(ConnectionParameters::DBAL_SQLITE_MEMORY);
+        /** @psalm-suppress InvalidArgument */
+        $this->assertInstanceOf(Store::class, Store::build($moduleConfiguration, $this->loggerStub));
+    }
+
+    public function testCanEnqueueJob(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $jobsStore = new Store(
+            $this->moduleConfiguration,
+            $this->loggerStub,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub
+        );
+        $jobsStore->runSetup();
+
+        $queryBuilder = $this->connection->dbal()->createQueryBuilder();
+        $queryBuilder->select('COUNT(id) as jobsCount')->from($jobsStore->getPrefixedTableNameJobs());
+
+        $this->assertSame(0, (int) $queryBuilder->executeQuery()->fetchOne());
+
+        /** @psalm-suppress InvalidArgument */
+        $jobsStore->enqueue($this->jobStub);
+
+        $this->assertSame(1, (int) $queryBuilder->executeQuery()->fetchOne());
+
+        /** @psalm-suppress InvalidArgument */
+        $jobsStore->enqueue($this->jobStub);
+        /** @psalm-suppress InvalidArgument */
+        $jobsStore->enqueue($this->jobStub);
+
+        $this->assertSame(3, (int) $queryBuilder->executeQuery()->fetchOne());
+    }
+
+    public function testEnqueueThrowsStoreExceptionOnNonSetupRun(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $jobsStore = new Store(
+            $this->moduleConfiguration,
+            $this->loggerStub,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub
+        );
+        // Don't run setup, so we get exception
+        //$jobsStore->runSetup();
+
+        $payloadStub = $this->createStub(AbstractPayload::class);
+        $jobStub = $this->createStub(AbstractJob::class);
+        $jobStub->method('getPayload')->willReturn($payloadStub);
+
+        $this->expectException(StoreException::class);
+
+        $jobsStore->enqueue($jobStub);
+    }
+
+    public function testCanDequeueJob(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $jobsStore = new Store(
+            $this->moduleConfiguration,
+            $this->loggerStub,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub
+        );
+        $jobsStore->runSetup();
+
+        $queryBuilder = $this->connection->dbal()->createQueryBuilder();
+        $queryBuilder->select('COUNT(id) as jobsCount')->from($jobsStore->getPrefixedTableNameJobs())->fetchOne();
+
+        $this->assertSame(0, (int) $queryBuilder->executeQuery()->fetchOne());
+
+        /** @psalm-suppress InvalidArgument */
+        $jobsStore->enqueue($this->jobStub);
+        /** @psalm-suppress InvalidArgument */
+        $jobsStore->enqueue($this->jobStub);
+
+        $this->assertSame(2, (int) $queryBuilder->executeQuery()->fetchOne());
+
+        /** @psalm-suppress MixedArgument, UndefinedInterfaceMethod */
+        $jobsStore->dequeue($this->jobStub->getType());
+
+        $this->assertSame(1, (int) $queryBuilder->executeQuery()->fetchOne());
+    }
+
+    public function testCanDequeueSpecificJobType(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $jobsStore = new Store(
+            $this->moduleConfiguration,
+            $this->loggerStub,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub
+        );
+        $jobsStore->runSetup();
+
+        $authenticationEvent = new Event(new State(StateArrays::FULL));
+        $authenticationEventJob = new Event\Job($authenticationEvent);
+
+        $queryBuilder = $this->connection->dbal()->createQueryBuilder();
+        $queryBuilder->select('COUNT(id) as jobsCount')->from($jobsStore->getPrefixedTableNameJobs())->fetchOne();
+
+        $this->assertSame(0, (int) $queryBuilder->executeQuery()->fetchOne());
+
+        /** @psalm-suppress InvalidArgument */
+        $jobsStore->enqueue($this->jobStub);
+        $jobsStore->enqueue($authenticationEventJob);
+
+        $this->assertSame(2, (int) $queryBuilder->executeQuery()->fetchOne());
+
+        $this->assertInstanceOf(Event\Job::class, $jobsStore->dequeue(Event\Job::class));
+
+        $this->assertSame(1, (int) $queryBuilder->executeQuery()->fetchOne());
+
+        $this->assertNull($jobsStore->dequeue(Event::class));
+
+        $this->assertSame(1, (int) $queryBuilder->executeQuery()->fetchOne());
+    }
+
+    public function testDequeueThrowsWhenSetupNotRun(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $jobsStore = new Store(
+            $this->moduleConfiguration,
+            $this->loggerStub,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub
+        );
+//        $jobsStore->runSetup();
+
+        $payloadStub = $this->createStub(AbstractPayload::class);
+        $jobStub = $this->createStub(AbstractJob::class);
+        $jobStub->method('getPayload')->willReturn($payloadStub);
+
+        $this->expectException(StoreException::class);
+
+        $jobsStore->dequeue('test-type');
+    }
+
+    public function testDequeueThrowsForJobWithInvalidId(): void
+    {
+        $repositoryStub = $this->createStub(Store\Repository::class);
+        $jobStub = $this->createStub(GenericJob::class);
+        $jobStub->method('getPayload')->willReturn($this->payloadStub);
+        $jobStub->method('getCreatedAt')->willReturn(new \DateTimeImmutable());
+        $jobStub->method('getType')->willReturn(GenericJob::class);
+        $jobStub->method('getId')->willReturn(null); // Invalid ID value...
+
+        $repositoryStub->method('getNext')->willReturn($jobStub);
+
+        /** @psalm-suppress InvalidArgument */
+        $jobsStore = new Store(
+            $this->moduleConfiguration,
+            $this->loggerStub,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub,
+            $repositoryStub
+        );
+        $jobsStore->runSetup();
+
+        $this->expectException(StoreException::class);
+
+        /** @psalm-suppress MixedArgument, UndefinedInterfaceMethod */
+        $jobsStore->dequeue($this->jobStub->getType());
+    }
+
+    public function testDequeThrowsAfterMaxDeleteAttempts(): void
+    {
+        $repositoryStub = $this->createStub(Store\Repository::class);
+        $repositoryStub->method('getNext')->willReturn($this->jobStub);
+        $repositoryStub->method('delete')->willReturn(false);
+
+        /** @psalm-suppress InvalidArgument */
+        $jobsStore = new Store(
+            $this->moduleConfiguration,
+            $this->loggerStub,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub,
+            $repositoryStub
+        );
+        $jobsStore->runSetup();
+
+        $this->expectException(StoreException::class);
+
+        /** @psalm-suppress MixedArgument, UndefinedInterfaceMethod */
+        $jobsStore->dequeue($this->jobStub->getType());
+    }
+
+    public function testCanContinueSearchingInCaseOfJobDeletion(): void
+    {
+        $repositoryStub = $this->createStub(Store\Repository::class);
+        $repositoryStub->method('getNext')->willReturn($this->jobStub);
+        $repositoryStub->method('delete')->willReturnOnConsecutiveCalls(false, true);
+
+        /** @psalm-suppress InvalidArgument */
+        $jobsStore = new Store(
+            $this->moduleConfiguration,
+            $this->loggerStub,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub,
+            $repositoryStub
+        );
+        $jobsStore->runSetup();
+
+        /** @psalm-suppress MixedArgument, UndefinedInterfaceMethod */
+        $this->assertNotNull($jobsStore->dequeue($this->jobStub->getType()));
+    }
+
+    public function testCanMarkFailedJob(): void
+    {
+        /** @psalm-suppress InvalidArgument */
+        $jobsStore = new Store(
+            $this->moduleConfiguration,
+            $this->loggerStub,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->factoryStub
+        );
+        $jobsStore->runSetup();
+
+        $queryBuilder = $this->connection->dbal()->createQueryBuilder();
+        $queryBuilder->select('COUNT(id) as jobsCount')
+            ->from($jobsStore->getPrefixedTableNameFailedJobs())
+            ->fetchOne();
+
+        $this->assertSame(0, (int) $queryBuilder->executeQuery()->fetchOne());
+
+        /** @psalm-suppress InvalidArgument */
+        $jobsStore->markFailedJob($this->jobStub);
+
+        $this->assertSame(1, (int) $queryBuilder->executeQuery()->fetchOne());
+
+        /** @psalm-suppress InvalidArgument */
+        $jobsStore->markFailedJob($this->jobStub);
+
+        $this->assertSame(2, (int) $queryBuilder->executeQuery()->fetchOne());
+    }
+}
diff --git a/tests/src/Stores/Jobs/PhpRedis/RedisStoreTest.php b/tests/src/Stores/Jobs/PhpRedis/RedisStoreTest.php
new file mode 100644
index 0000000..f29ce0c
--- /dev/null
+++ b/tests/src/Stores/Jobs/PhpRedis/RedisStoreTest.php
@@ -0,0 +1,377 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Stores\Jobs\PhpRedis;
+
+use Psr\Log\LoggerInterface;
+use Redis;
+use SimpleSAML\Module\accounting\Entities\GenericJob;
+use SimpleSAML\Module\accounting\Entities\Interfaces\JobInterface;
+use SimpleSAML\Module\accounting\Exceptions\InvalidConfigurationException;
+use SimpleSAML\Module\accounting\Exceptions\StoreException;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Stores\Jobs\PhpRedis\RedisStore;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Stores\Jobs\PhpRedis\RedisStore
+ * @uses \SimpleSAML\Module\accounting\Stores\Bases\AbstractStore
+ */
+class RedisStoreTest extends TestCase
+{
+    /**
+     * @var \PHPUnit\Framework\MockObject\Stub|ModuleConfiguration
+     */
+    protected $moduleConfigurationStub;
+    /**
+     * @var \PHPUnit\Framework\MockObject\MockObject|LoggerInterface
+     */
+    protected $loggerMock;
+    /**
+     * @var \PHPUnit\Framework\MockObject\MockObject|Redis
+     */
+    protected $redisMock;
+    /**
+     * @var \PHPUnit\Framework\MockObject\Stub|JobInterface
+     */
+    protected $jobStub;
+
+    protected function setUp(): void
+    {
+        $this->moduleConfigurationStub = $this->createStub(ModuleConfiguration::class);
+        $this->loggerMock = $this->createMock(LoggerInterface::class);
+        $this->redisMock = $this->createMock(Redis::class);
+        $this->jobStub = $this->createStub(JobInterface::class);
+        $this->jobStub->method('getType')->willReturn(GenericJob::class);
+    }
+
+    public function testCanCreateInstance(): void
+    {
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->moduleConfigurationStub->method('getConnectionParameters')
+            ->willReturn(['host' => 'sample']);
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $this->assertInstanceOf(
+            RedisStore::class,
+            new RedisStore(
+                $this->moduleConfigurationStub,
+                $this->loggerMock,
+                null,
+                ModuleConfiguration\ConnectionType::MASTER,
+                $this->redisMock
+            )
+        );
+    }
+
+    public function testThrowsIfHostConnectionParameterNotSet(): void
+    {
+        $this->expectException(InvalidConfigurationException::class);
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $this->assertInstanceOf(
+            RedisStore::class,
+            new RedisStore(
+                $this->moduleConfigurationStub,
+                $this->loggerMock,
+                null,
+                ModuleConfiguration\ConnectionType::MASTER,
+                $this->redisMock
+            )
+        );
+    }
+
+    public function testThrowsOnConnectionError(): void
+    {
+        $this->expectException(StoreException::class);
+
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->loggerMock->expects($this->atLeastOnce())
+            ->method('error')
+            ->with($this->stringContains('Error trying to connect to Redis DB.'));
+
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->moduleConfigurationStub->method('getConnectionParameters')
+            ->willReturn(['host' => 'sample']);
+
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->redisMock->method('connect')->willThrowException(new \RedisException('test'));
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $this->assertInstanceOf(
+            RedisStore::class,
+            new RedisStore(
+                $this->moduleConfigurationStub,
+                $this->loggerMock,
+                null,
+                ModuleConfiguration\ConnectionType::MASTER,
+                $this->redisMock
+            )
+        );
+    }
+
+    public function testThrowsOnAuthError(): void
+    {
+        $this->expectException(StoreException::class);
+
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->loggerMock->expects($this->atLeastOnce())
+            ->method('error')
+            ->with($this->stringContains('Error trying to set auth parameter for Redis.'));
+
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->moduleConfigurationStub->method('getConnectionParameters')
+            ->willReturn(['host' => 'sample', 'auth' => 'test']);
+
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->redisMock->method('auth')->willThrowException(new \RedisException('test'));
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $this->assertInstanceOf(
+            RedisStore::class,
+            new RedisStore(
+                $this->moduleConfigurationStub,
+                $this->loggerMock,
+                null,
+                ModuleConfiguration\ConnectionType::MASTER,
+                $this->redisMock
+            )
+        );
+    }
+
+    public function testThrowsOnSetPrefixOptionError(): void
+    {
+        $this->expectException(StoreException::class);
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->loggerMock->expects($this->atLeastOnce())
+            ->method('error')
+            ->with($this->stringContains('Could not set key prefix for Redis.'));
+
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->moduleConfigurationStub->method('getConnectionParameters')
+            ->willReturn(['host' => 'sample']);
+
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->redisMock->method('setOption')->willThrowException(new \RedisException('test'));
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $this->assertInstanceOf(
+            RedisStore::class,
+            new RedisStore(
+                $this->moduleConfigurationStub,
+                $this->loggerMock,
+                null,
+                ModuleConfiguration\ConnectionType::MASTER,
+                $this->redisMock
+            )
+        );
+    }
+
+    public function testCanCallRPushMethod(): void
+    {
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->moduleConfigurationStub->method('getConnectionParameters')
+            ->willReturn(['host' => 'sample']);
+
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->redisMock->method('isConnected')->willReturn(true);
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->redisMock->expects($this->once())
+            ->method('rPush')
+            ->with($this->stringStartsWith(RedisStore::LIST_KEY_JOB), $this->isType('string'));
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $redisStore = new RedisStore(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->redisMock
+        );
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $redisStore->enqueue($this->jobStub);
+    }
+
+    public function testThrowsOnRPushError(): void
+    {
+        $this->expectException(StoreException::class);
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->moduleConfigurationStub->method('getConnectionParameters')
+            ->willReturn(['host' => 'sample']);
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->loggerMock->expects($this->atLeastOnce())
+            ->method('error')
+            ->with($this->stringContains('Could not add job to Redis list.'));
+
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->redisMock->method('rPush')->willThrowException(new \RedisException('test'));
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $redisStore = new RedisStore(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->redisMock
+        );
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $redisStore->enqueue($this->jobStub);
+    }
+
+    public function testCanDequeueJob(): void
+    {
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->moduleConfigurationStub->method('getConnectionParameters')
+            ->willReturn(['host' => 'sample']);
+
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->redisMock->method('lPop')
+            ->willReturn(serialize($this->jobStub));
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $redisStore = new RedisStore(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->redisMock
+        );
+
+        /** @psalm-suppress PossiblyInvalidArgument, MixedArgument, PossiblyUndefinedMethod */
+        $this->assertInstanceOf(JobInterface::class, $redisStore->dequeue($this->jobStub->getType()));
+    }
+
+    public function testThrowsOnLPopError(): void
+    {
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->moduleConfigurationStub->method('getConnectionParameters')
+            ->willReturn(['host' => 'sample']);
+
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->redisMock->method('lPop')
+            ->willThrowException(new \RedisException('test'));
+
+        $this->expectException(StoreException::class);
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->loggerMock->expects($this->atLeastOnce())
+            ->method('error')
+            ->with($this->stringContains('Could not pop job from Redis list.'));
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $redisStore = new RedisStore(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->redisMock
+        );
+
+        /** @psalm-suppress PossiblyInvalidArgument, MixedArgument, PossiblyUndefinedMethod */
+        $redisStore->dequeue($this->jobStub->getType());
+    }
+
+    public function testThrowsIfNotAbleToDeserializeJobEntry(): void
+    {
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->moduleConfigurationStub->method('getConnectionParameters')
+            ->willReturn(['host' => 'sample']);
+
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->redisMock->method('lPop')
+            ->willReturn('invalid');
+
+        $this->expectException(StoreException::class);
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->loggerMock->expects($this->atLeastOnce())
+            ->method('error')
+            ->with($this->stringContains('Could not deserialize job entry which was available in Redis.'));
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $redisStore = new RedisStore(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->redisMock
+        );
+
+        // Suppress notice being raised using @
+        /** @psalm-suppress PossiblyInvalidArgument, MixedArgument, PossiblyUndefinedMethod */
+        @$redisStore->dequeue($this->jobStub->getType());
+    }
+
+    public function testCanMarkFailedJob(): void
+    {
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->moduleConfigurationStub->method('getConnectionParameters')
+            ->willReturn(['host' => 'sample']);
+
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->redisMock->expects($this->once())
+            ->method('rPush')
+            ->with($this->stringStartsWith(RedisStore::LIST_KEY_JOB_FAILED), $this->isType('string'));
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $redisStore = new RedisStore(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->redisMock
+        );
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $redisStore->markFailedJob($this->jobStub);
+    }
+
+    public function testThrowsOnMarkingFailedJobError(): void
+    {
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->moduleConfigurationStub->method('getConnectionParameters')
+            ->willReturn(['host' => 'sample']);
+
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->redisMock->method('rPush')
+            ->willThrowException(new \RedisException('test'));
+
+        $this->expectException(StoreException::class);
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->loggerMock->expects($this->atLeastOnce())
+            ->method('error')
+            ->with($this->stringContains('Could not mark job as failed.'));
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $redisStore = new RedisStore(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->redisMock
+        );
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $redisStore->markFailedJob($this->jobStub);
+    }
+
+    public function testSetupIsNotNeeded(): void
+    {
+        /** @psalm-suppress PossiblyUndefinedMethod, MixedMethodCall */
+        $this->moduleConfigurationStub->method('getConnectionParameters')
+            ->willReturn(['host' => 'sample']);
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $redisStore = new RedisStore(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            null,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->redisMock
+        );
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $this->assertFalse($redisStore->needsSetup());
+    }
+}
diff --git a/tests/src/Trackers/Authentication/DoctrineDbal/Versioned/TrackerTest.php b/tests/src/Trackers/Authentication/DoctrineDbal/Versioned/TrackerTest.php
new file mode 100644
index 0000000..a6800b5
--- /dev/null
+++ b/tests/src/Trackers/Authentication/DoctrineDbal/Versioned/TrackerTest.php
@@ -0,0 +1,216 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Trackers\Authentication\DoctrineDbal\Versioned;
+
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Module\accounting\Entities\Activity;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event;
+use SimpleSAML\Module\accounting\Entities\ConnectedServiceProvider;
+use SimpleSAML\Module\accounting\Exceptions\InvalidConfigurationException;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+use SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store;
+use SimpleSAML\Module\accounting\Trackers\Authentication\DoctrineDbal\Versioned\Tracker;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Trackers\Authentication\DoctrineDbal\Versioned\Tracker
+ * @uses \SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfigurationHelper
+ * @uses \SimpleSAML\Module\accounting\Stores\Builders\Bases\AbstractStoreBuilder
+ * @uses \SimpleSAML\Module\accounting\Stores\Builders\DataStoreBuilder
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Factory
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator
+ * @uses \SimpleSAML\Module\accounting\Stores\Bases\DoctrineDbal\AbstractStore
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store
+ * @uses \SimpleSAML\Module\accounting\Stores\Data\Authentication\DoctrineDbal\Versioned\Store\Repository
+ * @uses \SimpleSAML\Module\accounting\Helpers\HashHelper
+ * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
+ * @uses \SimpleSAML\Module\accounting\Stores\Connections\Bases\AbstractMigrator
+ * @uses \SimpleSAML\Module\accounting\Stores\Bases\AbstractStore
+ *
+ * @psalm-suppress all
+ */
+class TrackerTest extends TestCase
+{
+    /**
+     * @var \PHPUnit\Framework\MockObject\Stub|ModuleConfiguration
+     */
+    protected $moduleConfigurationStub;
+    /**
+     * @var \PHPUnit\Framework\MockObject\MockObject|LoggerInterface
+     */
+    protected $loggerMock;
+    /**
+     * @var \PHPUnit\Framework\MockObject\MockObject|Store
+     */
+    protected $dataStoreMock;
+    /**
+     * @var \PHPUnit\Framework\MockObject\Stub|HelpersManager
+     */
+    protected $helpersManagerStub;
+
+    protected function setUp(): void
+    {
+        $this->moduleConfigurationStub = $this->createStub(ModuleConfiguration::class);
+        $this->moduleConfigurationStub->method('getConnectionParameters')
+            ->willReturn(ConnectionParameters::DBAL_SQLITE_MEMORY);
+        $this->loggerMock = $this->createMock(LoggerInterface::class);
+        $this->dataStoreMock = $this->createMock(Store::class);
+        $this->helpersManagerStub = $this->createStub(HelpersManager::class);
+    }
+
+    /**
+     * @psalm-suppress PossiblyInvalidArgument
+     */
+    public function testCanCreateInstance(): void
+    {
+        $this->assertInstanceOf(
+            Tracker::class,
+            new Tracker(
+                $this->moduleConfigurationStub,
+                $this->loggerMock,
+                ModuleConfiguration\ConnectionType::MASTER,
+                $this->helpersManagerStub,
+                $this->dataStoreMock
+            )
+        );
+
+        $this->assertInstanceOf(
+            Tracker::class,
+            new Tracker($this->moduleConfigurationStub, $this->loggerMock)
+        );
+
+        $this->assertInstanceOf(
+            Tracker::class,
+            Tracker::build($this->moduleConfigurationStub, $this->loggerMock)
+        );
+    }
+
+    public function testProcessCallsPersistOnDataStore(): void
+    {
+        $authenticationEventStub = $this->createStub(Event::class);
+
+        $this->dataStoreMock->expects($this->once())
+            ->method('persist')
+            ->with($authenticationEventStub);
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $tracker = new Tracker(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->helpersManagerStub,
+            $this->dataStoreMock
+        );
+
+        $tracker->process($authenticationEventStub);
+    }
+
+    public function testSetupDependsOnDataStore(): void
+    {
+        $this->dataStoreMock->expects($this->exactly(2))
+            ->method('needsSetup')
+            ->willReturn(true);
+
+        $this->dataStoreMock->expects($this->once())
+            ->method('runSetup');
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $tracker = new Tracker(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->helpersManagerStub,
+            $this->dataStoreMock
+        );
+
+        $this->assertTrue($tracker->needsSetup());
+
+        $tracker->runSetup();
+    }
+
+    public function testRunningSetupIfNotNeededLogsWarning(): void
+    {
+        $this->dataStoreMock->method('needsSetup')
+            ->willReturn(false);
+
+        $this->loggerMock->expects($this->once())
+            ->method('warning');
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $tracker = new Tracker(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->helpersManagerStub,
+            $this->dataStoreMock
+        );
+
+        $tracker->runSetup();
+    }
+
+    public function testGetConnectedServiceProviders(): void
+    {
+        $connectedOrganizationsBagStub = $this->createStub(ConnectedServiceProvider\Bag::class);
+        $this->dataStoreMock->expects($this->once())
+            ->method('getConnectedOrganizations')
+            ->willReturn($connectedOrganizationsBagStub);
+
+        /** @psalm-suppress PossiblyInvalidArgument */
+        $tracker = new Tracker(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->helpersManagerStub,
+            $this->dataStoreMock
+        );
+
+        $this->assertInstanceOf(
+            ConnectedServiceProvider\Bag::class,
+            $tracker->getConnectedServiceProviders('test')
+        );
+    }
+
+    public function testGetActivity(): void
+    {
+        $activityBag = $this->createStub(Activity\Bag::class);
+        $this->dataStoreMock->expects($this->once())
+            ->method('getActivity')
+            ->willReturn($activityBag);
+
+        $tracker = new Tracker(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->helpersManagerStub,
+            $this->dataStoreMock
+        );
+
+        $this->assertInstanceOf(
+            Activity\Bag::class,
+            $tracker->getActivity('test', 10, 0)
+        );
+    }
+
+    public function testCanEnforceDataRetentionPolicy(): void
+    {
+        $retentionPolicy = new \DateInterval('P10D');
+
+        $this->dataStoreMock->expects($this->once())
+            ->method('deleteDataOlderThan');
+
+        $tracker = new Tracker(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            ModuleConfiguration\ConnectionType::MASTER,
+            $this->helpersManagerStub,
+            $this->dataStoreMock
+        );
+
+        $tracker->enforceDataRetentionPolicy($retentionPolicy);
+    }
+}
diff --git a/tests/src/Trackers/Builders/AuthenticationDataTrackerBuilderTest.php b/tests/src/Trackers/Builders/AuthenticationDataTrackerBuilderTest.php
new file mode 100644
index 0000000..8a27f1a
--- /dev/null
+++ b/tests/src/Trackers/Builders/AuthenticationDataTrackerBuilderTest.php
@@ -0,0 +1,111 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SimpleSAML\Test\Module\accounting\Trackers\Builders;
+
+use Psr\Log\LoggerInterface;
+use SimpleSAML\Module\accounting\Entities\Authentication\Event;
+use SimpleSAML\Module\accounting\Exceptions\Exception;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+use SimpleSAML\Module\accounting\Services\HelpersManager;
+use SimpleSAML\Module\accounting\Trackers\Builders\AuthenticationDataTrackerBuilder;
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Module\accounting\Trackers\Interfaces\AuthenticationDataTrackerInterface;
+use SimpleSAML\Test\Module\accounting\Constants\ConnectionParameters;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\Trackers\Builders\AuthenticationDataTrackerBuilder
+ * @uses \SimpleSAML\Module\accounting\Helpers\InstanceBuilderUsingModuleConfigurationHelper
+ * @uses \SimpleSAML\Module\accounting\Services\HelpersManager
+ *
+ * @psalm-suppress all
+ */
+class AuthenticationDataTrackerBuilderTest extends TestCase
+{
+    /**
+     * @var \PHPUnit\Framework\MockObject\MockObject|LoggerInterface|LoggerInterface&\PHPUnit\Framework\MockObject\MockObject
+     */
+    protected $loggerMock;
+    /**
+     * @var \PHPUnit\Framework\MockObject\Stub|ModuleConfiguration|ModuleConfiguration&\PHPUnit\Framework\MockObject\Stub
+     */
+    protected $moduleConfigurationStub;
+
+    protected AuthenticationDataTrackerInterface $trackerStub;
+    protected HelpersManager $helpersManager;
+
+    protected function setUp(): void
+    {
+        $this->moduleConfigurationStub = $this->createStub(ModuleConfiguration::class);
+        $this->moduleConfigurationStub->method('getConnectionParameters')
+            ->willReturn(ConnectionParameters::DBAL_SQLITE_MEMORY);
+        $this->loggerMock = $this->createMock(LoggerInterface::class);
+
+        $this->helpersManager = new HelpersManager();
+
+        $this->trackerStub = new class implements AuthenticationDataTrackerInterface {
+            public static function build(
+                ModuleConfiguration $moduleConfiguration,
+                LoggerInterface $logger
+            ): AuthenticationDataTrackerInterface {
+                return new self();
+            }
+
+            public function process(Event $authenticationEvent): void
+            {
+            }
+
+            public function needsSetup(): bool
+            {
+                return false;
+            }
+
+            public function runSetup(): void
+            {
+            }
+
+            public function enforceDataRetentionPolicy(\DateInterval $retentionPolicy): void
+            {
+            }
+        };
+    }
+
+    public function testCanCreateInstance(): void
+    {
+        $this->assertInstanceOf(
+            AuthenticationDataTrackerBuilder::class,
+            new AuthenticationDataTrackerBuilder(
+                $this->moduleConfigurationStub,
+                $this->loggerMock,
+                $this->helpersManager
+            )
+        );
+    }
+
+    public function testCanBuildAuthenticationDataTracker(): void
+    {
+        $authenticationDataTrackerBuilder = new AuthenticationDataTrackerBuilder(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManager
+        );
+
+        $trackerClass = get_class($this->trackerStub);
+
+        $this->assertInstanceOf($trackerClass, $authenticationDataTrackerBuilder->build($trackerClass));
+    }
+
+    public function testBuildThrowsForInvalidTrackerClass(): void
+    {
+        $authenticationDataTrackerBuilder = new AuthenticationDataTrackerBuilder(
+            $this->moduleConfigurationStub,
+            $this->loggerMock,
+            $this->helpersManager
+        );
+
+        $this->expectException(Exception::class);
+
+        $authenticationDataTrackerBuilder->build('invalid');
+    }
+}
diff --git a/www/assets/css/src/custom.css b/www/assets/css/src/custom.css
new file mode 100644
index 0000000..cb8acd7
--- /dev/null
+++ b/www/assets/css/src/custom.css
@@ -0,0 +1,42 @@
+.center {
+    text-align: center;
+}
+
+.pagination {
+    display: inline-block;
+}
+
+.pagination a {
+    color: black;
+    float: left;
+    padding: 8px 16px;
+    text-decoration: none;
+    transition: background-color .3s;
+    border: 1px solid #ddd;
+}
+
+.pagination a.active {
+    background-color: #4CAF50;
+    color: white;
+    border: 1px solid #4CAF50;
+}
+
+.pagination a:hover:not(.active) {background-color: #ddd;}
+
+
+.accordion {
+    cursor: pointer;
+    transition: 0.4s;
+    border-bottom: 1px solid #cbcbcb;
+}
+
+.active, .accordion:hover {
+    background-color: #ccc;
+}
+
+.panel {
+    display: none;
+    max-height: 0;
+    overflow: hidden;
+    transition: max-height 0.2s ease-out;
+}
\ No newline at end of file
diff --git a/www/assets/css/src/default.css b/www/assets/css/src/default.css
new file mode 100644
index 0000000..ee7abd9
--- /dev/null
+++ b/www/assets/css/src/default.css
@@ -0,0 +1,424 @@
+:root {
+    /* */
+    --main-text-c: #181E3C;
+    --main-bg-c: #F5F5F5;
+
+    --heading-text-c: #5B6186;
+    
+    --caption-bg-c: #F0F2F9;
+    
+    --table-border: #F0F2F9;
+
+    --nav-bg-c: #F8F8FC;
+    
+    --button-bg-c: #4859B2;
+    --button-text-c: #ffffff;
+
+    --link-c: #4859B2;
+
+    --main-font-family: Raleway;
+    --main-font-weight: 500;
+    --mainfont-size: 18pt;
+
+    --table-font-size: 18pt;
+
+    --large-font-size: 24px;
+}
+
+/* raleway-300 - latin-ext_latin */
+@font-face {
+    font-family: 'Raleway';
+    font-style: normal;
+    font-weight: 300;
+    src: local(''),
+         url('fonts/raleway-v28-latin-ext_latin-300.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
+         url('fonts/raleway-v28-latin-ext_latin-300.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
+  }
+  /* raleway-regular - latin-ext_latin */
+  @font-face {
+    font-family: 'Raleway';
+    font-style: normal;
+    font-weight: 400;
+    src: local(''),
+         url('fonts/raleway-v28-latin-ext_latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
+         url('fonts/raleway-v28-latin-ext_latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
+  }
+  /* raleway-500 - latin-ext_latin */
+  @font-face {
+    font-family: 'Raleway';
+    font-style: normal;
+    font-weight: 500;
+    src: local(''),
+         url('fonts/raleway-v28-latin-ext_latin-500.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
+         url('fonts/raleway-v28-latin-ext_latin-500.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
+  }
+  /* raleway-600 - latin-ext_latin */
+  @font-face {
+    font-family: 'Raleway';
+    font-style: normal;
+    font-weight: 600;
+    src: local(''),
+         url('fonts/raleway-v28-latin-ext_latin-600.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
+         url('fonts/raleway-v28-latin-ext_latin-600.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
+  }
+
+/* ======================= */
+/*     mobile-first body   */
+/* ======================= */
+
+body {
+    display: grid;
+    grid-template-rows: 4em auto auto auto auto;
+    grid-template-columns: 1fr 18fr 1fr;
+    grid-template-areas: 
+    "header header header"
+    "nav nav nav"
+    ". banner ."
+    ". main ."
+    "footer footer footer";
+    min-height: 100vh;
+    font-size: var(--main-font-size);
+    font-family: var(--main-font-family);
+    font-weight: var(--main-font-weight);
+    margin: 0;
+}
+
+/* ======================= */
+/*     header and logo     */
+/* ======================= */
+
+header {
+    grid-area: header;
+    background-color: var(--nav-bg-c);
+    color: var(--link-c);
+    display: flex;
+    text-align: center;
+    width:100%;
+    z-index:999;
+    flex-direction: row;
+    align-items: center;
+    justify-content: flex-start;
+}
+
+#logo {
+    margin-left: 2em;
+}
+
+/* ======================= */
+/* Nav with hamburger menu */
+/* ======================= */
+
+#nav{
+    grid-area: nav;
+}
+
+nav {
+    width: 100%;
+    padding: 1em;
+    text-align: left;
+    display:none;
+    background-color: var(--nav-bg-c);  
+}
+
+nav ul {
+    margin: 0;
+    padding: 0;
+    list-style: none;
+    display: inline-flex;
+    flex-direction: column;
+    flex-wrap: wrap;
+    align-items: left;
+    justify-content: flex-end;
+}
+
+nav li {
+    margin-left: 0.5em;
+    margin-right: 0.5em;
+    color: var(--alt-color);
+}
+
+nav > ul > li {
+    font-variant: normal;
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    margin-top: 0.5em;
+}
+
+nav > ul > li > a {
+    color: var(--banner-font-family);
+    text-decoration: none;
+    display: flex;
+    flex-direction: row;
+    justify-items: center;
+}
+
+.nav-toggle {
+    display:none;
+}
+
+.nav-toggle:checked ~ nav {
+    display: block;
+}
+
+.nav-toggle:checked ~ div {
+    display: none;
+}
+
+.nav-toggle-label {
+    margin-right: 1em;
+    margin-left: auto;
+    display: flex;
+    height: 100%;
+    align-items: center;
+    align-self: flex-end;
+}
+
+.nav-toggle:not(:checked) ~ .nav-toggle-label {
+    margin-left: auto;
+}
+
+.nav-toggle-label span,
+.nav-toggle-label span:before,
+.nav-toggle-label span:after {
+    display: block;
+    background: var(--link-c);;
+    height: 2px;
+    width: 2em;
+    position: relative;
+}
+
+.nav-toggle-label span:before,
+.nav-toggle-label span:after {
+   content: '';
+   position: absolute;
+}
+
+.nav-toggle-label span:before {
+    bottom: 7px;
+}
+
+.nav-toggle-label span:after {
+    top: 7px;
+}
+
+.navicon {
+    display: inline-grid;
+    justify-content: center;
+    align-content: center;
+    width: 2em;
+}
+
+/* ======================= */
+/*     Banner              */
+/* ======================= */
+#banner {
+    grid-area: banner;
+}
+
+#banner div {
+    color: var(--link-c);
+    background-color: var(--nav-bg-c);
+    margin: 2em;
+    padding-left: 1em;
+    padding-right: 1em;
+    padding-bottom: 1em;
+    padding-top: 2.5em;
+
+    border-width: 1px;
+    border-style: solid;
+    border-color: var(--link-c);
+}
+
+/* ======================= */
+/*     Main                */
+/* ======================= */
+
+#main{
+    grid-area: main;
+}
+
+/* ======================= */
+/*     Table               */
+/* ======================= */
+
+table {
+    margin:1em;
+    padding:1em;
+    margin-right: auto;
+    font-size: var(--table-font-size);
+    width: 100%;
+}
+
+th {
+    text-align:left;
+    padding:0.5em;
+    word-wrap: break-word;
+}
+
+td {
+    text-align:left;
+    padding-left:0.5em;
+    padding-right:0.5em;
+    padding-top:1.25em;
+    word-wrap: break-word;
+    border-top: solid 1px var(--table-border);
+}
+
+th a {
+    text-decoration:none;
+}
+
+td a {
+    text-decoration: none;
+}
+
+.dropdown {
+    float:right;
+}
+
+/* ======================= */
+/*      dropdown-box       */
+/* ======================= */
+
+.dropdown-toggle {
+    display: none;
+}
+
+.dropdown-container {
+    padding:0em;
+    border:none;
+    display:table-cell;
+}
+
+.dropdown-label {
+    float: right;
+    height: 1.25em;
+    position: relative;
+    top: -1.5em;
+}
+
+/*
+.dropdown-toggle:checked ~ .dropdown-label:first-of-type {
+    border: 3px solid black;
+}
+*/
+
+.dropdown-box {
+    background-color: var(--caption-bg-c);
+    display:none;
+}
+
+.dropdown-toggle:checked ~ div.dropdown-box:first-of-type {
+    display: block;
+}
+
+/* ======================= */
+/*     Footer              */
+/* ======================= */
+footer {
+    display: flex;
+    text-align: center;
+    width:100%;
+    z-index:999;
+    flex-direction: row;
+    align-items: center;
+    justify-content: flex-start;
+    grid-area: footer;
+    color: var(--link-c);
+    background-color: var(--nav-bg-c);
+}
+
+footer div {
+    margin: 2em;
+}
+
+/* ======================= */
+/*    desktop provisions   */
+/* ======================= */
+@media only screen and (min-width: 768px) {
+    body {
+        display: grid;
+        grid-template-rows: 4em auto auto auto;
+        grid-template-columns: 3fr 0.5fr 16fr 0.5fr;
+        grid-template-areas: 
+        "header header header header"
+        "nav . banner ."
+        "nav . main ."
+        "nav footer footer footer";
+        min-height: 100vh;
+        font-size: var(--body-font-size);
+        font-family: var(--main-font-family);
+        font-weight: var(--main-font-weight);
+        margin: 0;
+    }
+
+    header {
+        background-color: var(--main-bg-c);
+    }
+
+    #nav {
+        background-color: var(--nav-bg-c);
+    }
+
+    nav {
+        width: 100%;
+        padding: 0em;
+        margin-left: 0em;
+    }
+
+    nav > ul {
+        width: 100%;
+    }
+
+    nav > ul > li {
+        font-variant: normal;
+        font-size: 90%;
+        display: flex;
+        flex-direction: row;
+        align-items: center;
+        padding-left: 1em;
+    }
+
+    nav > ul > li > a {
+        width: 100%;
+    }
+
+    nav > ul > li > a > span > img {
+        display: inline;
+    }
+
+    .nav-toggle ~ nav {
+        display: block;
+    }
+
+    .nav-toggle-label {
+        display: none;
+    }
+
+    /* ======================= */
+    /*    pagination           */
+    /* ======================= */
+    .center {
+        text-align: center;
+    }
+
+    .pagination {
+        display: inline-block;
+    }
+
+    .pagination a {
+        color: black;
+        float: left;
+        padding: 8px 16px;
+        text-decoration: none;
+        transition: background-color .3s;
+        border: 1px solid #ddd;
+    }
+
+    .pagination a.active {
+        background-color: #4CAF50;
+        color: white;
+        border: 1px solid #4CAF50;
+    }
+}
\ No newline at end of file
diff --git a/www/assets/css/src/fonts/raleway-v28-latin-ext_latin-300.woff b/www/assets/css/src/fonts/raleway-v28-latin-ext_latin-300.woff
new file mode 100644
index 0000000000000000000000000000000000000000..dc1fdae677d4997655cbbe569035de51f2283ee4
GIT binary patch
literal 38728
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%0D?p2EDx$L~p5r5Cb&z0f)AXeeI;_e4OK6~pe
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
F7y$7ExyS$j

literal 0
HcmV?d00001

diff --git a/www/assets/css/src/fonts/raleway-v28-latin-ext_latin-300.woff2 b/www/assets/css/src/fonts/raleway-v28-latin-ext_latin-300.woff2
new file mode 100644
index 0000000000000000000000000000000000000000..5c74b981a826de2286fead05d18752c0cd0fe787
GIT binary patch
literal 30788
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
Vr|U~UUrhdYZ}abG%*ne%831W8b_oCg

literal 0
HcmV?d00001

diff --git a/www/assets/css/src/fonts/raleway-v28-latin-ext_latin-500.woff b/www/assets/css/src/fonts/raleway-v28-latin-ext_latin-500.woff
new file mode 100644
index 0000000000000000000000000000000000000000..90f9b9a12c51cd868aca772a613e2340384b0dc6
GIT binary patch
literal 38156
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
N&y+AJ;|~J^0{}Sv@vHy<

literal 0
HcmV?d00001

diff --git a/www/assets/css/src/fonts/raleway-v28-latin-ext_latin-500.woff2 b/www/assets/css/src/fonts/raleway-v28-latin-ext_latin-500.woff2
new file mode 100644
index 0000000000000000000000000000000000000000..902e197fceb48075a90088328383c444f32e9a19
GIT binary patch
literal 30184
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

literal 0
HcmV?d00001

diff --git a/www/assets/css/src/fonts/raleway-v28-latin-ext_latin-600.woff b/www/assets/css/src/fonts/raleway-v28-latin-ext_latin-600.woff
new file mode 100644
index 0000000000000000000000000000000000000000..7f9315eb18875ac0612c71f34cd4acbb161bb41f
GIT binary patch
literal 39596
zcmXT-cXMN4WME)mn6-vMh=GBD(TIV85h4N-MaJ$fu5Jtrj8hmG7?v|IFls1h$n&`e
z_y;pEFxfCL==m}*WI5bQEKqb04s~K+Fz8`mV4TOmz^o;2CdKO?tZ&4?V5Gyqz~INg
zz>tu5!OlH6#4&_{!Kj9Tfx(i2fx+cz!x`1&+{6L~2BRGe3@m{R3~YP?bAR<Gmz5|m
zFqrc|^>&FYVA`2hke<uHU>?K3z<!;9fq%*)$$3%fiNysB4E81r3=AAlERdd4na03i
zZ^OV4u!VtP#*@8!PEX26O-x~6=>NdLz+eW#LW#0RGBQ#V85kyLFfcGEFfcHvus>s!
z%*ZXNU|^Ww!N9=m!@$5P@KP=6UQT{;A_K$ZDGUrOaSRMBUFpe=vbl*B1q=++zd-dW
zuzVNj%S+5nWnh>g!oa}jz`($?#`S0Vwu1cP5(b8uAq)%*!XUN(=Q9`;6r~n0FwD$g
zU|@7)U|^i%uW^{E;#N{ZN<z|uWCmt8L4{~(4W<{8e2E+!3<g~Lx6k(7q<k}{>e9L!
zDZ4$>Rw<mEbYNNjta~bv7tLp@z4Q%!@h|1R-D1&8d@tL+II}5+o-jy}32OIoN>lti
z!S#e%ihL1=W!oI5bBfa^WS`J|BKL`-vTcvkJw^F_8HtT%ISYJeXJmGky;)#eosrtw
zC$n&?sa0v0UhE?6@E5mCca^pWGCbY?f%)_rr4WXSTRE4Qb5a6D7%o_E&Aq)X_x9W0
z^@3}*=N(qc+OSPhFZ(ucw(`6grtfCFkE!|0$jlIOfJw%|Oixjlf6Y4ckb8`)txLYz
zZeTk0cJ|co4&42h7;Fz5w2Nb#Vo;ir#-OKvGg@MnszUo(2X*He-{SqQ|6ch$INed-
zf#c}+;5m_-@6DUY)&H_{;^dc|Dw74y*o0&UW#3A>mA0u}v{PnldR3CH@+qIwKHS-x
zZ?+r_*H&GfwvRROno$|+HP13unQvJ^M=iE~ve><29p{d{PYc5Zo^3n!@?hYKOMj(i
zi?6QwUta&F^1<IbzwO^mRC&Dj!Q%(PM?z0Nlz%S&{PV5l=hM$`ziEH&{OR?F*5A9&
zx_#P@`9J3$HA<ezXx3=XWX~4L<;k^*XPThs7poVhWi?7)%vIDY^nU25u>VcVe)?_c
zhvhHwkKFEP?3nApZFpdv<3+xj)Qxsd8vBmjP^~dLW3hTi?~jQr-7VK#W*+%<Wb%@U
zPdc7_KN)<|U6W1IPg73weDJRzx1eR0R$ZPc>1EOT$0#ms&-oXpLY+8wy0S{PmUqQX
zn>F=T!PBW>8#XyD{*s+(`pl!%tyO%YV%Cv{851R(CRRVO{OJ|=C3si!JSNGc!?U)Q
zT<R70zz}_)&^0Pj<K)D{2^Fup`W8yO<L!HC`tB~@VISATw6ruov8>ASie-kskA6O$
z+ix7pExOe)FM5*-cZbO`QSKvB#=V`pSXbyU2oz|revD#xaY5<(@|Ri59(cLko*z3Q
z*o~`ar|AKm^1JUOe61MLzD`={Sk-@7Yt7}^k!QV(KCUQkbbG)4*s|-<duDH1%lxWj
zZ*9auvq^I2WRClo?+z(FRlM@zlB~?*cTV?Qx>_5X<hN<Ql)*u7y{J{<e<#hZoA!Cm
zwN<NsM=k5`+ULE<_)<^LngyH8ZIkz0+4ea#|3KEZkH^kf7W+-h^6;F>cJ+I0<2L()
zj(pi{JCgqg>M?)WFDzR>YwH`u={m7`g3)i87kE1z|12DP_)_xyU0&{Sk&E;EXU>e8
z8T#jcK)##g)Ghfl^xkA{n6}EJ^={8=xzC=`>9LOv?7DqZTkpa%D-kJScC(FF0xIO}
znoNw?Rr9aw^eaA-v3r|)_W!f)Cr{mPB>b0s<oA?2vHshNAJhLwuKddN%;IQT^V~P3
zVK3gR^$IU@pCeK?i+Ro?rQ0_yeNOyVbnNsYvv-BF-m=}!|HWE%V$-8VmyP#`?d!Jg
zDVVnZ=D`V(?;pD@nAn}-nwYnCQ)lcsZM{RkclMu%EN_fCF4xEP(VClqGjsoYG3|9T
z_@x>3*_0cqBm$5AHhfY$LG5@2pPsbonqK8~kvT;UavlfWZ6*XiZ;bZ6pvJT|&Nw>K
zNZ{k4v@?2>Yp?xWV$(H4U0I0r$Q9jbAEK;3Kby^GG_hKlUnYG{dyL@?*UR#SPW$R3
zt2cMO-1b4ZN6_#{*f%Yv^~QJP#Z5YEk6gI&X0iUFjR`!JCtXyttJYf`Uvb{;N`z`o
zPqB>1H<OCF8Xv4mAO7C?_Fq5mvnw061+qqq$5qrXJgV7t@Z_Z@E3W=9VsBxc+F&);
zXs_kjyj`azr}rFXee`9b{b8=K?<TDa*h-xJw;2EEh*m3@xVcqVVpCMvl=gVG=a*Qu
zPiB>!{9j}hqolP~#dneG>c4!^Z&%M*ptVLUtU7I_;p@%5`B!Ex`5zWk<f%31NYE=6
zjy;by_6w}K#wKFfB6j}H&GdWy)5UJ?Nm#MwmaY_|e)FyWwNKN_U-X|cZ}tB)VfVTD
z`%UlncYCYk+A&x>)@F4+y&#))_1-s=r<Y1T-gU3eOLX5$-7`KD>m?WG-S<!yes6H@
zlgOLQ_~!Q(Z%PZE2YdfFT{Yugw^KsvT=UIqCme2`-v4>uxe0s)k-5*;c6f7~5!;vb
z`b^1;-g`xH{0EYB0|i{m?H@~T1ed<spk(x9;muQ`u3kU(Ah`cma^&|by`_`)YscHH
z==i`?^I_{o`~NpX1e`wdCvx}~D9yUyqPFU+yZOUT*BB*%`7JJrhMqZ*MnS@px2V~@
zJn6t>G;z9%$O46z8a{>5VV6>tnmj$}<~n({mKy(6pSY|UHCGnO{mgXn=DK)m$|Bjf
zn!fJA)6SJFmAUKdT4mVa#gn9ADtV6MmC>my={=bTEYvPc@I14S^RsWY*v46WYf@$R
z-Z+r=Ys2)zJr6Y0CC+Oa&orKs%q4!NM6Y<R<eevG#XC>iihXEE*Ll<$c`|!5m%4n|
zY5&HYYx93~zy0Ozcw=P(*D<@+0Eutfa}E`{2#QWz+_mO}OmK+n(;Z1#X6hpGCoR^B
zcpXe#8YZ<)WA3FwU&$$*uTL$~xf5je^x3vgTKfD`<6A41C~2KC77Z_qTd~CJQ_#}T
zY2jMyXIWe|WL&j=8dr$)*8qX9MuJz}YehZ(`il6P1ezXpxh!)wxJ37Y)6q*py1_DQ
zFG%g)^i{3XY}S%nYn;87DXYysH|vd6e$k6{Cs!V?S{Ebt=|eyrzkNT0=$3rdhJ-5{
z*Y8=kbb9Ud+B=DAJ9T9W_;)15zcBsoB6sED{C7K(cC~k<YQ8_WYS!)ruck>&n>Ed9
z+OKJ0dHbVw$7Vf#w~9ILRm$UY?>6q*!9MHpwTyMqtDe4_cJ0AR-D%D1*7of%mMh}7
zwb8lvZdZH%(d%o~*2LbGFDo@)nf>$R)xQOy`^&z4wzsY3{4#BtHRGjKRsyUwdF7XV
z^)GOBoKWL)_E7R*Y&yo`+`zEuh`IzvKa<OX#xyS1n}O~nSAMkpU8%V?#7lNsTK1*M
zVUe>`b<XN}H!}%2sO2y@-H@6)@%O%8KT~5AgrDyXzxMp+@BO!TrrSTiC!aaVNh@>7
zWJk5gl*!JjTF29!^(H^A=MSE7%4C^w^UQY%Vw-0=GZxQ$?)U7td^@Yok_k#(mFg`Y
z^xkirq57uhae>ahH6_d40#Ecr9i8v~{qiicElXwJRyw>YS!5jh;#9MZ$nik)U7rnX
zUwG<QU2fm^W%2&M@}=t-c~S%_dBXJCZkSD}X)~N7X!CG~y5va>H)FMZGQFuXk7piG
zI`zo3sM3ogaoHs^f3KZ~3oMuHI{Ze1%iKNl-ItvclFo}hd{z+sCvt_WcXgStALm5n
zeydN9ADqyb^m=EXfW15G^$E8>UR+^f_n61E=v#4WR#45&d*X)!A08Em(ZBoE$XUmA
z@rT;$KIPK{N|)>}`sT#ZcTd2qRpXvakcVn-iO~s_?wq0(E>C|<opAc>yER;)E8R--
zp6boIFeS}oxwDOJ$&&Tw|5mj8<5B2Wd}2K3c*UHFJr5(xO(s6CY!t8ToIX=zdi&Ck
z*EaMBP1`&vbWIv>cBH%J>zfDEUhbNyo0BSi`=+2gpY_#aMi2GMJ}-R#eZ%zHH_sW^
zEsrGj6`1_<ki53d;u(v&<<U$%snnQD+0#!?JY8kFb1AR?WaH8&XZoL>$-U_Nap4NC
z(3Qt@Lzc6dt`x18xw?$6bftT()P)JwnJ&q*E}bzf&)yxy5naUpy-0rTquPsqw=Cn$
z&2+D}I`&`A)<NCsa_c&q6V4weu8_W4IYaKt67jt+o#THg)?eNDDT9Go(nYR$Ym9S?
z^T~9H!;%MuKdN7x+>;`*IFN18#-3yw;R?5tf8BrEOV96BTg83;=<LPMA3yFC`a9`Y
z_=<ghR)66CxM#(TqdMQecm0T89JDoW@2@?Ly*Ww6HA=UH>ZNi;_vznB`@iYO;*9AZ
znt$w=_QlDoOKR#u(LX+CZS>fKpTxB7)(MwBe|xvZpWq#lf7d#Nt_qwRz0<dM&Cysp
z^M#scGyJ?ux6jV4t$lY~`Aa%OC6D6#hc?F^_oVQw|Dd)0qjcPJ-n!H8D<*HRn7!03
z>$FCqrFP`etZN&ll}_0-k2mL1Uw#^Q^vz>sWfGk4ujo(VEZ;brzjlB7-Z#ni>=q{!
z`HEW>zcUZ?mnm+VJm-<g{L|)d>qETHht0OSvQ+MCri1glC4#+~r|uRln7Zv_UDV~a
zZCe)G@@p8+ec>a%>yrY1=I7lP=eECe^sl-&+wRL!`M*==t5-~#*pp;(U3>ni`9d4x
za_?)3-u<}M+MAPCI9lsgk>ZU>Z$vNUp6&a>b?Qa@n~j=Rt~6hn_PU<0-%!);L5IEd
zqn<F8(}Ja26(pl3Sj$#cmn@%kspDVP2jip<IV%<{Um>Ae<Yw!$C9G1HSMuB*@6LS*
zJ_TB;b9uu5FZ}#;$063gf8J01@HlZ*fz;)h2Ys}+Za(ua-MF3UnbG}MN14QeJOq!v
z2?_60tC|_=rXSoJ7w7k->{h<=wD2o4%onS^dS{f#sqHjn#q`^cuP>JU_$Fid1|2!Y
zW$j15lz3T5emqlfdb*+L>FY;ct<8^l`7}S~rD}MUY2nf*qI0%hH$V65_3LLrQ(g2z
ze>|IZWc$|r7vtkSzg=H`SSJnag7ZH4`)<C2I6~!D*~U|)Wp9%<<=e02k-4~ie(_e<
zq#uzxG(WZ&P5+-KZ?ER^Yp+O<r}A7LqmxRrWwZiszRK2<T~g_uw(Akhz^Vf^VjCtn
zb!nun42gE*JRNybD{OPy)-{W#e9cLieC6I5v2B}r-@dtU{{5C+p=x)I=GlGuEB9?v
z|6iF03hfqW1eb(Z<oy?(^F(C%&zRhfL%M;wZ=G{r1x&BHvYe53=VUjNWt!#3pWd4F
zzvJC<)7%Vi>sy~!NSQY@@+kEm^tvz5HtD=Un{m_gM{j?v)8BV1{N(@gMM3x1POp}}
zaYD`P^u@I?Z|8eW{(Cvl_>RZz2`Hs-^vsh_S1;Ys9CT}9o}GR68Y_62BJ<vN%D0t=
zGJVq7j2}09bx7(IYb5A>e#Adz!q!AaZp|efN%sP+?>)5@+uX8r-A1&sX8{}UwdU8V
zix)mI?s?d=z`$;`+h5OD^E$dB&j?wrQ19`INUYl$<+Xll@lrQ|+d233mX_bx7962=
zXX*^=xz`@K{aTM2=2C8Y+dETrqr6N%Pfm$0bU8KWuiM}KYyK_odds=-S4fUt%<BIq
zH$ULH)u4T{@PvA2RN)n$vr&nUd``{_yt{wW3~jwnf4T0*&lO+CHFeVFNyh8yEpL7g
z@wviW+rRi+hkNChDc18fLf37RtN-(ihc(^v-qA+sElKK=*4|it{auo8N6*?|l%jfv
z!jq!S+Mx@zuC6$@_KvIYtV=!5N<OSvp^Q{S$d~Hd9D8inpTaZw&)zGg(*q9`g>CA(
zx+YQgwMMF~^o=EJZ$lHtgk#ocxlgt1zHzpF-~GdJ-!{%?mU$x3Zh0tBJOB8TSB1yt
zJWyF~an^Nbh3D^3IjvLs_fN0i+RLKV67gET_1mY9?-$SR>0BK!HS3O3X;#4GsG_B2
zr7OH`UtMl!yW^=Wb$Lo!-_Gcp8Hzb4ZSS0}-LmN~tPGJAF7EjBLNR$(Udi*sstc3j
zzAWRfec5g#VS9>!&8WkMZT4lJ!gG*Fe86e?$J5QI>tavgI!KwUb}#SVhLd{|*MHg@
zeEWCYmp$kIFPWzO`eOGUk@bdk-lp|Gd{%!v4lS5>xcG8itlFBzEPb=(Pye<Z=hq(k
z-g^5@eA>LN-ai~`&iqN7`qSBCrNE*oB}P-WAA9xDQuSs0)Jf$+mjBG3tdXg7ew9Dr
zR`H^3B_a2hYzT?gYQ47Ob@RoDV}^Ei-(=tIXxgpqw@tWRD0xZt#y)#rPj%%b8TNU>
zzq2Ria31-mpR``LbHBjjg3?mw+aKpdL@qAarkl8XR{j@P<TgpP`njiRZ@ooV1@*qV
zb1K#ZT=KW?&?v!L0c+nBuAC=cF>!juOwW&;YY!a*SHPFFPG~(u6#buka*U&IoHE<C
zSvgMes8~DJIyg?Yuk$i2mLn^R1G7s`YOIQxT{-jo+R613C8W(dl`cIw<NNU)QYE~!
z<vL~^9NnA)isiJk-?`o|4&7t7YyP#5zXPQcqi<c5OYYror2Sjrm0P*oGIraSuKB+%
zOt1T5{<%6NQtp5Q+eG)Isg1CxUit|V)fXp0nn=bU>q?(b_V^i4ZWp*He6@A;mAS#!
z;_O57|1G(<WJYpi?uYO4OWX~+Bj3GWy_)ys#j3BF%+fcHq^%Z>Zi#Mv&pnlQ>k^;r
zz)3NtdYkjAz4rcAQJu?^dw{=b(uya!fmQc{h5l(Azr1hK<ExV_?<vfD?EAE0vrFIU
zi7tFwu4Z|BJ+dajKv{V0VfS|*o`k<E2>rz8zx%N9yAKW4CTgBr`1b!l#q-JkWW+qN
z(~~t{rp)L(V{X5C$vruq&=p>$tBSSDFSaZ*S!`MR5?*^}f4%w~)QDPp&Sl<n*0?9C
zacPq-eh6B7(a0;}oLAV!S*B}JWtXl=XP*7YHW3zq_tcMm#~OiGynYzw{((i{)n8Hb
zVno*{e!ukO9{;4B*Mr`fPO8p)m0cOqx+>(c*s9>>Syv`SZ(Zpe`zmlgo5_<~s}`L1
z&3rav_gcX%0^6R*y?bgGC24%mKl|2&X=PiMFTVJa`IR560p;a~+QzN_lm7LqhY7eY
zP~=gapU9KWlH8Me+^FxP&jU%@pPLV!(G2mpw*SnN&HX(Yd#kpC+C`g#_D$VXu|BB!
zqjqiNw&xeOpKOdONe<c*?x`7~#r5RJ?V>FXeEX)ISvj@n)s#8AG%X+RQ=S=I9y`1A
zdN=oyXKE|MHJ+w<Z?t{)&HvS{{VTI~AKeua``aP*w@2*l)$2r8W=CJy+WhKPU}^5-
zt=FE&YVJE!xkWB%U*sA4p!;4|w$~T4R|j9Zs5K)#f>HeT=cFo6ovkd2LWl1>ndNXb
zW%qn-wRGjx%g${(D|u?}!WgbQ(`L9%iF*H|)z+?eUeVp<Tj#YFWlem)c8<j(+r{67
z6<^=F_y6iV%agX(*^7BL{yy_FSf(^GDyHyArF)HtuIG`ooys=Fzpe?^=e`ejO6i${
zQUT81`Lt;Am6Zo`!}_zhvIA%Dy5nd2Zh;-|4>{hSjJ+8?+)+jP_K)o9&iH2>_5UfE
zn{oVnra${y2Y0y-JB8=IbPBI?G~e~vyXwN^_>0~5z9fn)mOO27%(!uRW!Nj<CzWvz
zT;m?4svVzaU^Ep}m9F=A8D80Y|ASTjhv>TFv-cdmT_Gl#W;okY#9(^myxcS9%rOU?
zxHK2dC_hsRsaumf4U<G%v$EG2eRSXmgd_ux`n9LNR)5_*G2QiIz$eLL1#TZ&OmC@!
zdo{-_N^~AeoM+*hTQBGxvC!1;Jm3EXAv?TtKOXyVdV_HY?{TN21;?Imp7Yp7e8&mZ
zQ#;Q*uW^*AlVnv2I^-O<%Al8PN$^CUO()daWAZMwfoixNt*@>uP&=C;XXT>XqPw%b
zdS`#%!c8K7cCP>jfZP*BU3b((x&Pb4K;>3Q&+FS?So=hM%T|A*OOsaz9=h0bu?SSI
z%q@3XAz`~zzS=5e@~gQ^e{Fa%_kz=@>wVK&*9CH}K71e}_r&E(f169E%ez`1`rlK=
zb-G2q<;@fkt(GfON{kNKFG*?JrWv`=_rwpQ<CD(!Xlof4Caqbtl>g=RyII~V<kH%n
zCC2@j81}3q?DPGnDcqJfFU@=VG$q&a=3T-4ld5$W-*Mp&_B`|7FVa$Hn`KgTWX^km
z!}4zO65m}EJ0kZ^cwDvn5VVQse}9$|@1+QldL6mwt;ym?FA1Jp8-IV&%%1v{Yo{NL
zwU(a0@%XxolUqX{US60~bY+6xzR<b0zBXT*9=*94nzU`&&$YHfwmr6Ark>oZ)$+c*
z_nXz>$a97BxMQ9OJykh(MEuA(k&Y$qT?SK4v?lnuhJ$;ACzkHam30nKTC&<CRw?cD
zk)179*L?k3_K@%4IhVM30*9jy&rO;kcdlSs@to&O;yYa|r~jOz-!a!x;N)77M6Jva
zg}Ght>?iANI;lAQ*|t)V)61ROBGNijOJ9b%`fNUGVyl&Cnw@JNEP9(~<64bvmyAE!
zsH&&Lt6zO>eOk6}jmX-iCU@rf{Jrh`>-sl8&a=YqH>9L?zMg$p@?25h=a>gd(|4F%
ze$1V;)l6Wb6U4TZNv>v=PcF^rQ|!94b;mu$b>CO4)Vye9sFhgyV_rpl{GRAtk44I3
ztZ!-RaBscq?7h{<cdgIwYkRL0eYF<)9`rCe^U>}9uP24S{$G9aw2#g8n=>o+)gQ|E
zRdS`n_1A3CZ#qYRW&Du;X7ws=R*SBp>;H*Mmv<kQte^i>=K0P8u6lvzQth5|pSif$
z!KG`OYUm6%)=Mirz@rU%XPxh^D4kH9^r^w<R_D2rh1&d&B)@*WUpDc!^A>$*pYue)
z<a@?_$3O+=ggSrE?aPIAbD5VudG6)8ZVS()O^G3gUS05t`WJF)%k+7nOVhhEmT&M`
zvGvNl<^P^<-hLtO<jU1guJBE57Abk2d-Pk&#iui0WZL*ox^{d^mG~UPN!MP_d3yeT
zCEM$T_C8DgZcH$7gl6R=*Nbx!Ast}nZNKfMc_C%E|BhSW4zT3om}JT06>1+sYX0T-
zWrii~n<(>i*Y(?zb${<nIbC-zaJ5i%T3zmW>9?Vm<DS0>O<KRVGw^5W`%4_P9TI#{
zvyO*PQvQ(}K7W#w{Mv7Kqr4tZUiW34cCAp+{z}z!+kfWrb05F(?u&c=LfC7qjOUTp
zQx^MM?>ci)eDZrE-LfMqv#&@0oBDcg!QRt-7VkQ~%N8E{s^_{o(tG9G)WXKa{xxgk
z{~o>mE7Z_)&(<<c!y;cB|MGKpj&Qjb?E60V`J}!7Ro>fO+}vJpy0m}A3psEvs%T@^
zE1%3xW7T;(R;OAEtv$I>|NM$8%l~h!I1)bT<B!wVA5EO<bNKAZO~u7UvhI94&bxlQ
z!l#<%J~RIIXSZryu8D>DTq~DM^kbWuGSQcB>Ixq{^P^QVy3vr9TbF33%et!~*A|(T
z?wnh7$FWxGgRRsjW~qxacF$SN>6__R9Q9+L>i18|?;aoj(-QV)%KVFMWq;;;vw;j#
z{AtQ7c|QHi0`>iiz=IUm-@=;>kWT-UWVgjzd6HW}#q7Lik)Jnr+MMU!bHaPinUvI8
zuHc!+O42@bZK<1j{Ri**&usgjmhU+kz2~fte^EN5pkMu7Hiw%#!b8zj<a6J}r@QwY
zPnuTXli9iD-P$eh-~(F+?B>1zckesJ!nh5<75u?{`#&1b&Od*B-G95MGhNo+Stv67
zXt>aOE2+P~_gnK@AN`Z@NB)~t-fOk!sgts!!`r$JN}P&|XQ}=>bz{hn{GO$&T)+Xg
z(}aKO*Ap{4FCJsQ)#O*Qj61e+!g8mwB9)@a-yX47UF^CjRIgurPbjS2dW-zmuPVJ?
z7tOpiLF%GkV&sa2e}62DGj?A;Q&y`^TQ<n)-}Ot6s;d9|t>1b4`~Ge2ZbhYOyLDxs
zmgc->jNX1DOXlCxYx%h|1(a5A)m$>k%}NqnNQ5lfR6eiB@H40EqooU#C(k?-vdnO<
z<e89n&=9JOy7cp13bdE`anIk_d&!305n9vGM^^59sMLQpWuecG?z?~9p07Ty=GJq(
z*6yIEUtyH(&voas-Y=UPc<3*5Bx;}Os>9Mf@zqrumHq|HwU%CcT|YlTdA7&8Woq*y
zYNpgA6{@ICN}tEmHsQ_XK9%(A^?|2?r+zvidTMT|`=<Ec8ir<FZ|uG5iwr{+B6s_~
zES2xSFrV>>VM|ThXNi8}Nrpb(^uCEKGwOYLCSh6bb#3R*Ur#_{dvi$tUbK$#0k!v+
za$$o*qA$NX&nyt%{qw^2>Kmu+z7;n#%RDl0w^&v0F+~*83CvXq^Ip5wSN2s<|1XmT
ziq}tdo%h{&+pvD=-u-!zo@=&jj{AAzfScLIn^xb#PTBlC;nx>`UX%O(GrxW|)fh>O
z<veeEr#04|I&jhD<j<n5&oVyEJ#qd`<t@40>vl(74$;1=6On$^>%LTy@}3i2zEK(9
z=7wdTad-CEcXamS7Xq47Pi=^(c`kV(_I|GIEy0~71%LZ|zD2Ls^hpH|^L(6nH0N2s
zff%9pcO<>_6BJuT0?(BG`g$bzpKDO{%ndAypPh)XUb@KQk48nl`p0<Wu2=P|iQeq<
zt&J@2NiH*hG?g-#<DQz<9e%y%VE#|p{7+)}#>RE`WAnJ7!^D3+pIsvk8g=<#=Ju)Y
z)S~;@Tc^!TpR(cJ+`I(k**jiX?>|s7eZGe3)Vt1llmGe^K{BR6@XJ|C?arm~v7SlY
zcVA5p?8r5u(N8p|eR}-n*q(FqM2lv=IeQZ7r87S+l-}>1{r(=<CXK%P{`c-5kAF5}
z^&GzKyStv-`dkb5OVqkN;~Y;~)hdhbn`ag_>^vjh3>m$Cy!Pa3nF&qt9tZRHXTJ!)
z9Q0w*>Uf^g7+d2fMmOVO1K(bkb@tu>2ir60R)~9K<h|qm>R;da>gJ0{7p6MzegAD=
zY*C+4<lI@%jB=&?e3BV>JZ9<yh+SK|@6}(v<`T6Tb=;)Jb~;~HlDpb!U#NAj|1fD)
zwLP~{t%;NV*>vrzYW@GXs6UR?!Do`fDt7INyS)X}L74r%eB=Fn^VHp^FUj0l_IlIJ
zuj%v3XRXw-zON~J@@d=46@O={ZikHL#mh!PTCCAiXI@Q&2J+>qKRPeXz^z*8J^HhB
zjO8^qrcb@G+3Q)N_7?r$VVPT=rhH+a-yL~|OEVzre6HPlE=TSE+4I#lo|u+eHA84$
z=s%&%@_ReCKA5<D?f$*&-#qq2SDvg~XK`Nicl<?b5AE~Lb!%g1rLdUZ+@|?$<}06W
zr@lWnO7_#;j_y(C>u%M4Wd9<3)8encR`ceh2;a`ReYCFlTlcHes=uda3+w&<ZLDf?
zInr5)Eq?d&Co!6p=aWqI@4fiHKGU&Hll2~p>Qs|UClx>~r-edOADcVt={nE)^hbZ8
z@+Cc=YfQcuqkTmElC6wqtW=-*^fx%lRc;mDhK&H;+J%wDzwd*N!zZRpkqE>#`upkE
zj=%l|lY-|gi@BrUzTenuMc$mk_KAniFEUB)j*4o(b!DO6*A@QEQbp>$89u@9%r0du
zje~U&p9flkJAnSTzBtbB`R^q4GG&6N*v%&aou}@Joq3v89^ASrWU<xuB5~ggFXLI4
zr`Opy)w4}FF7Qcm-5J;rmC%0H+V8I_qAYq}o_Qd8J030TUH-TEPf`{n&E0uflmAf{
zoO5Kv?|yhY`QI_K{;Ks!kXFprMb1|aLB<grycbQI7g&A2)9Z#~<e$E(U;W#Bwmh|b
z$o=VEYVIrh)yIR^YA;i{zw6(XIgzIythfKQTE)w-+CNzN_wPSVVIJ0xd*^v{qYPN4
z8J!M<<p2D$N#Oe7(UIBrGCSk>B&_RA)#7^{L*BmHpXQEKwB%iCzn_y92nm9q!`p7(
zDfLa%P0US<&08*49x$J+roZh^gPX}Sz2_ND!Lu&T5!;u)^7@YOALz}4k_(^8o-oe0
zzBp5_<f(Xx@cws);x9GN`_ly;HH+PkRt*I9NuHIMf1K;M;XF>8vzs3o!-iIOMkU{y
z=v;j$<RNI{D}2uT(74Cud(KJ!nRfr9TK-3~&O#%I7pH5eu08}Ar>@DKb1>*>g`}!Z
zy6WnPvr^YK^#xtq+}Qi>aobxx>#bAcXP*4`_HEvyzdMZY&pTOk%=A38k*@LFX#Qu`
zjsMI9CMMa<(DLEtcNcAW`Qr3qNEa{nlkYY}AMgIwx%tm#JiGI@m^;z?-NU$di>J=2
zv|pR)9DVEJyuNMr2{xA?t>;eycVC=4{AGdq-WR^|zb^G3`CWR9n_1$7!Y7F}t`bQ(
zme8rT#M_WY>|$P-(-y~!9qpc~)#oaG-K)4b{0iUI370~J7hmtR5!W|vvV9%9&D+hP
zy2oA2MSe!MTan4z)7OkIt#-})7q_nWkF$p&N~ZKwoId;OC)D8`**(XvPuyqs{juOL
z;|80y3Fiys9v8Y9wWV*}iWsPSm%hw;M(Pt|aM@H@)&BF=9Y_HhnYC^wM#lZT^=wX}
z_U#+z_{y>vAp^8;67_%IIM2ve)Nxqm;fl&PhCeIrJO_{6YnJneUq2AsQ}yc9<JniI
z^e@&5St_+XV6N1aCDVSUppECBl_}o7p>>1m_X7Rz7rpM+!a})y$~%;?*yC5zg`O{h
zbfv>C=l!@6zWRfTvgFZ>V>jx-{rq``!N1)%uTQ_art{<cslR`o`s;r3`!ap4|Llw7
zZ`+;xeP!}r+oRtvw`i~XqgwK#$kfSmpU|p+saYY<!`>|dH->**>UV!}p5c>(lilIU
zp5u}yCCoNL%d5uw+giaRmWn9tk#n4WMO~Lw>JP5jlA>PMJ!evd`r@XbLe*99c1iiA
zj$<ZI^Pay_DJ>HIe^;SYX!V(`JL0rTxgY*7^ordzE9g+{n`ilcn!o3Phqj-(+&wiR
z$nxYAujxUO|9huwYWgOd&SC1TXD;zLw!G(CaCpZ1p8sDfUiwt@9I5Cu^zmAwup}<l
zQ2<;JYcAV7ryNo?&B(tE$uT-p7ooQnbBy-gfQ-1u$ZnqV>)4E^DL0Tt+naVKJ<`4Q
zx;OHa@ca3pe*e-|mwl35!PWWwT-M9S*}?6*t}M3W%{Z}jYUTXdNj!-*1*)%H(sx~$
z%3kTgeWmxEjSqj-rS5xQ7V7`~aPRxq`Dfa$NdL8aR+WEN?cdvl^_$*a@0+VKr|EtG
z%l=j0|I5_=u2;Ecxz<np-o3BO@{;tv>O`G*QuE5AXzR0AF{|zf%C~db)y}GkKe#?v
zBFEI&dgHAP#)e)tvuif5UlhU{w6#vjHT+0%udbcxHVY}EN!9Z=mG9ge+_ZOnpI^<t
z`v=2RGdv^Er=pVg#A|AC&AxdkY}>}UvLE-WJPOA$8@0~v{cVvxYsi%FxgF2I0~Pm{
z?t={$<@|+q`9GXqTA~%DdrGA{r|85}wfr~X3$?C7MvJzd*^UUYxh9JYK?9u6KGrS$
z7QaZ$ZaZX<^QiZt-<iJBw=VU4D=E3dTsQLuv~-zpU#E1jHUH)2d0!Tp*S_$!{}nyG
zehMTLY+Gb^MA{45XBY0P22XP)ui4ZGp2`nDb<6zuzs^fP4zEA^_dValqPeJ}eUi^E
z9gNC!|5GiL*3%yQFk*(*oMR<v2F7*;&E>Xw_g>teG2y=Yk#`+ieinnP)PCu|uhM4T
ziaXSIWWCiNre~+)o7v|#NzI9fp2Da2IZHSEvHGVuxBfRJ$9?-*A9?dv`uwZkvR`XG
zU$>3<+a*4g>!IheJJoJoFZ^fqw&(v({ogW$$BLr)tRG9J+dQAaJu$>nCb|3Zn!jyo
z_X}HpcTYH-Qv3wk^7J{s0Xi=D^PWuvsEKtbYTXsx{rC2llpK!N(kcG0`o_cNsg3Ne
zmJ=Onts$2@)SJO&x>pFFJ?GAn4dw1_*^ctbMSI?5%@hP>lOK8Sg>pGJ&p0c?HRJT2
zfYW#N;hj*4{imyS(mF5RpIf!pP34|v$#h6zp7So_ivVmy!r~uzPC)1Lmh~;NAM-S~
zS^trDd&hX}ns(2j4^hwO)Ssz7UL1LQTkdY&tlQfjUD=i^o!q|l?1q@i*KX$VpUxJ3
zd1L!9`tX0{Cl6n>TT~uMe?I;E|F@5Kya{%dUYWG|l<L|iUDqB=-E>x4`^nU+p_ktM
zU+r)9JaF}`D;~|8rn04q^PZA4(MZ3vV9sJyqvEYs?yH_+)d<w{=`0HLn&KV2D5g#5
zY0(so>x*1=@~NKU)eOvY=`1Stni3tb=*}der(shxwqG-x`L<+_-?eXFG|Csc@6@(E
zb@yf9JIDT_{HiIxFD$+@U+(F_FB<$y-76(*PaQ5@{q9QOuITSCD^^WW4_<21s`a!o
zL{tC52Di`Jk7r$Zx<zySBHv2c+*7YJgYUV_{*-oWO8JFlduE$G-Md9oexdJAjoeem
zGlK2hXMa+?HD&#UWi^w{Qsr|`CEl8%yhYPJGq~^KGMVMRmaelu<=&d|{=%}FezT{)
zw`kgbT6Ql;{_?UvO=eH0Z_(Vp)c2=t?kV|<;APIw{!aP)qWP<Ft5@KPE%GN!0_Nv@
z5uTZ5|2F;ZBXOh4e|M?hSvJYf)l<}K)uJVayEVhSA~L(Co_n)S;-!NRr=jYRDFVSx
zKAeVgJ6@joc~@ort&rKS=bzn*I(tj+@|wL$i+g&Ej82`<PzE!+tn7lXaau*j{&;c7
z-PZ2a$H4yns@O@IuP<q2I(nLVtqKh4os=~tWbqPd)wLR#SCwam+0H7yyLh?MGB!g~
z!Ov0OURODb?wvW)zt+%1x6N&nyYc3UCeogwDxniX9D`itQ?-6s1izSk#_5;Iwq?oL
zR@<H(yT*Uh-ff0pT8rf&txeq)(LCwAd1b|A-dnCNT+5eRdhy!iyVAw1&$!Nr&d@dp
zPgvKnGd1*MQC!^TO4juYUd9=6RR`YaKIA51wrGQ3Yp+I*bD}g?c3?#Jp(v4Si#CY0
z8VBBZr*X#al6#u`)5j)<kN>XFeIi`b^hUULkyOnj|4EO(JhABu(Un=rpLsB&He$2P
z`kVg0C3WRCpMUms#nnTBx0hSKE8j2nv4MTd3U=EW$DQR)Jx=7$p5|_|NY&<5pzce<
z{-+;z9RFN#NLVoD(#($aZZ)QlRtw%=JguiN{#dQ#_hWkt^Y2K1@B5{idS`lJ{Ig{y
z=1X^Kp7qVlUC^82=bG<#G|XuGvYn=9*Ji$*`Ek#@32%~1=loe;{OG>)^3|`{7HKdv
z<iB^CG1Jj0Td6N=jgpe~`!nSkHa+UC>b3sA=6$h!DQ#r3B-i8igl&qs&bQjm@JdP=
z8KtD0I5gqb1S|fX%Ww70lYZ#7<6`OJ*KRum^ID`Ix<wdnTa@j3y=$JRt+o^tR#m#%
z`>vT05f}-9f?+M9iLMbKYGU}GC98g%HLuDmxx3=dinx0_M7LitPRTm)rCTxEIj!vs
z&rHcpTK_(^Y~*AY{#JRYK5EtmlZQEn?zJ>?N(=X?&GE6ARbZ5udFW`%YEE(Cb!s~D
zSJhdcF)%Px+)6#iyhb)rpzUFKU*v4*D|vTTY|Gv4zE%2)Tfni>0P_`+cNc8SHP6sj
zoBaB$%K7d8&9zxN0@_9H_06s3OF7)qx>+d4qi6QyB<_!$D@!IVo}Au0`@qX1TQnc<
znBj5Ox5#$lya@`Y_hjBPpFeB;+5TtcpV!-&bpH=|Vv%0D?p2EDx$L~p5r5Cb&z0f)
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

literal 0
HcmV?d00001

diff --git a/www/assets/css/src/fonts/raleway-v28-latin-ext_latin-600.woff2 b/www/assets/css/src/fonts/raleway-v28-latin-ext_latin-600.woff2
new file mode 100644
index 0000000000000000000000000000000000000000..977bba2f6a116b7e0f3896d067e3abd0df9a34b6
GIT binary patch
literal 31544
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
BvGxD}

literal 0
HcmV?d00001

diff --git a/www/assets/css/src/fonts/raleway-v28-latin-ext_latin-regular.woff b/www/assets/css/src/fonts/raleway-v28-latin-ext_latin-regular.woff
new file mode 100644
index 0000000000000000000000000000000000000000..067a3fda39dc8080c117a8c8540438b43b106516
GIT binary patch
literal 38932
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

literal 0
HcmV?d00001

diff --git a/www/assets/css/src/fonts/raleway-v28-latin-ext_latin-regular.woff2 b/www/assets/css/src/fonts/raleway-v28-latin-ext_latin-regular.woff2
new file mode 100644
index 0000000000000000000000000000000000000000..fb296a5863312faceb7d1f5af3ec9899744757d5
GIT binary patch
literal 30932
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

literal 0
HcmV?d00001

diff --git a/www/assets/css/src/icons/activity.svg b/www/assets/css/src/icons/activity.svg
new file mode 100644
index 0000000..d209dc1
--- /dev/null
+++ b/www/assets/css/src/icons/activity.svg
@@ -0,0 +1,3 @@
+<svg width="26" height="20" viewBox="0 0 26 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M12.9974 12.4207L14.2807 9.5332L17.1682 8.24987L14.2807 6.96654L12.9974 4.07904L11.7141 6.96654L8.82656 8.24987L11.7141 9.5332L12.9974 12.4207ZM3.60573 16.679C3.13906 16.679 2.74045 16.5138 2.4099 16.1832C2.07934 15.8526 1.91406 15.4638 1.91406 15.0165V2.03737C1.91406 1.5707 2.07934 1.17209 2.4099 0.841537C2.74045 0.510981 3.13906 0.345703 3.60573 0.345703H22.3891C22.8557 0.345703 23.2543 0.510981 23.5849 0.841537C23.9155 1.17209 24.0807 1.5707 24.0807 2.03737V15.0165C24.0807 15.4638 23.9155 15.8526 23.5849 16.1832C23.2543 16.5138 22.8557 16.679 22.3891 16.679H3.60573ZM3.60573 15.3665H22.3891C22.4863 15.3665 22.5738 15.3276 22.6516 15.2499C22.7293 15.1721 22.7682 15.0943 22.7682 15.0165V2.03737C22.7682 1.94015 22.7293 1.85751 22.6516 1.78945C22.5738 1.7214 22.4863 1.68737 22.3891 1.68737H3.60573C3.50851 1.68737 3.42101 1.7214 3.34323 1.78945C3.26545 1.85751 3.22656 1.94015 3.22656 2.03737V15.0165C3.22656 15.0943 3.26545 15.1721 3.34323 15.2499C3.42101 15.3276 3.50851 15.3665 3.60573 15.3665ZM3.22656 15.3665V1.68737V15.3665ZM1.2724 19.5957C1.07795 19.5957 0.917535 19.5325 0.791146 19.4061C0.664757 19.2797 0.601562 19.1193 0.601562 18.9249C0.601562 18.7499 0.664757 18.5992 0.791146 18.4728C0.917535 18.3464 1.07795 18.2832 1.2724 18.2832H24.7224C24.9168 18.2832 25.0773 18.3464 25.2036 18.4728C25.33 18.5992 25.3932 18.7596 25.3932 18.954C25.3932 19.129 25.33 19.2797 25.2036 19.4061C25.0773 19.5325 24.9168 19.5957 24.7224 19.5957H1.2724Z" fill="black"/>
+</svg>
diff --git a/www/assets/css/src/icons/conn-orgs.svg b/www/assets/css/src/icons/conn-orgs.svg
new file mode 100644
index 0000000..9b497e8
--- /dev/null
+++ b/www/assets/css/src/icons/conn-orgs.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="18" viewBox="0 0 24 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M11.3557 13.0833H12.6682V7.3375L15.1474 9.875L16.0807 8.9125L11.9682 4.82917L7.8849 8.9125L8.8474 9.875L11.3557 7.3375V13.0833ZM2.60573 17.75C2.13906 17.75 1.74045 17.5847 1.4099 17.2542C1.07934 16.9236 0.914062 16.525 0.914062 16.0583V1.94167C0.914062 1.475 1.07934 1.07639 1.4099 0.745834C1.74045 0.415278 2.13906 0.25 2.60573 0.25H21.3891C21.8557 0.25 22.2543 0.415278 22.5849 0.745834C22.9155 1.07639 23.0807 1.475 23.0807 1.94167V16.0583C23.0807 16.525 22.9155 16.9236 22.5849 17.2542C22.2543 17.5847 21.8557 17.75 21.3891 17.75H2.60573ZM2.60573 16.4375H21.3891C21.4863 16.4375 21.5738 16.3986 21.6516 16.3208C21.7293 16.2431 21.7682 16.1556 21.7682 16.0583V1.94167C21.7682 1.84444 21.7293 1.75694 21.6516 1.67917C21.5738 1.60139 21.4863 1.5625 21.3891 1.5625H2.60573C2.50851 1.5625 2.42101 1.60139 2.34323 1.67917C2.26545 1.75694 2.22656 1.84444 2.22656 1.94167V16.0583C2.22656 16.1556 2.26545 16.2431 2.34323 16.3208C2.42101 16.3986 2.50851 16.4375 2.60573 16.4375ZM2.22656 16.4375V1.5625V16.4375Z" fill="black"/>
+</svg>
diff --git a/www/assets/css/src/icons/download.svg b/www/assets/css/src/icons/download.svg
new file mode 100644
index 0000000..f024321
--- /dev/null
+++ b/www/assets/css/src/icons/download.svg
@@ -0,0 +1,4 @@
+<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="32" height="32" rx="2" fill="#3C4A94"/>
+<path d="M7.93333 25.9999C7.4 25.9999 6.94444 25.811 6.56667 25.4333C6.18889 25.0555 6 24.5999 6 24.0666V19.9333H7.5V24.0666C7.5 24.1777 7.54444 24.2777 7.63333 24.3666C7.72222 24.4555 7.82222 24.4999 7.93333 24.4999H24.0667C24.1778 24.4999 24.2778 24.4555 24.3667 24.3666C24.4556 24.2777 24.5 24.1777 24.5 24.0666V19.9333H26V24.0666C26 24.5999 25.8111 25.0555 25.4333 25.4333C25.0556 25.811 24.6 25.9999 24.0667 25.9999H7.93333ZM16 20.9999L10.4667 15.4666L11.5667 14.3999L15.2333 18.0666V5.7666H16.7667V18.0666L20.4333 14.3999L21.5333 15.4666L16 20.9999Z" fill="white"/>
+</svg>
diff --git a/www/assets/css/src/icons/dropdown.svg b/www/assets/css/src/icons/dropdown.svg
new file mode 100644
index 0000000..e71599d
--- /dev/null
+++ b/www/assets/css/src/icons/dropdown.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="10" viewBox="0 0 16 10" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M8.00013 9.56644L0.466797 1.99977L1.53346 0.933105L8.00013 7.39977L14.4668 0.933105L15.5335 2.03311L8.00013 9.56644Z" fill="#5B6186"/>
+</svg>
diff --git a/www/assets/css/src/icons/fppp-logo.svg b/www/assets/css/src/icons/fppp-logo.svg
new file mode 100644
index 0000000..c546a9c
--- /dev/null
+++ b/www/assets/css/src/icons/fppp-logo.svg
@@ -0,0 +1,37 @@
+<svg width="195" height="35" viewBox="0 0 195 35" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M39.2445 16V4.05909H47.2668V6.09409H41.5655V9.17182H46.3082V11.0555H41.5655V16H39.2445ZM52.1952 16.1682C51.4888 16.1682 50.8497 16.0505 50.2779 15.815C49.7061 15.5683 49.2184 15.2376 48.8147 14.8227C48.4111 14.4079 48.0972 13.9258 47.8729 13.3764C47.6599 12.827 47.5534 12.2495 47.5534 11.6441C47.5534 11.0162 47.6599 10.4276 47.8729 9.87818C48.086 9.31758 48.3943 8.82985 48.7979 8.415C49.2016 7.98894 49.6893 7.65258 50.2611 7.40591C50.8441 7.15924 51.4944 7.03591 52.212 7.03591C52.9296 7.03591 53.5687 7.15924 54.1293 7.40591C54.7011 7.65258 55.1832 7.98333 55.5757 8.39818C55.9793 8.81303 56.282 9.29515 56.4838 9.84454C56.6969 10.3939 56.8034 10.9658 56.8034 11.56C56.8034 11.7058 56.7978 11.8459 56.7866 11.9805C56.7866 12.115 56.7754 12.2271 56.7529 12.3168H49.9416C49.9752 12.6644 50.0593 12.9727 50.1938 13.2418C50.3284 13.5109 50.5022 13.7408 50.7152 13.9314C50.9282 14.122 51.1693 14.2677 51.4384 14.3686C51.7075 14.4695 51.9878 14.52 52.2793 14.52C52.7278 14.52 53.1482 14.4135 53.5407 14.2005C53.9443 13.9762 54.219 13.6847 54.3647 13.3259L56.2988 13.8641C55.9737 14.5368 55.4523 15.0918 54.7347 15.5291C54.0284 15.9552 53.1819 16.1682 52.1952 16.1682ZM54.4825 10.8536C54.4264 10.1921 54.1797 9.66515 53.7425 9.27273C53.3164 8.86909 52.7951 8.66727 52.1784 8.66727C51.8757 8.66727 51.5897 8.72333 51.3207 8.83545C51.0628 8.93636 50.8329 9.08212 50.6311 9.27273C50.4293 9.46333 50.2611 9.69318 50.1266 9.96227C50.0032 10.2314 49.9304 10.5285 49.9079 10.8536H54.4825ZM64.5504 16V14.6209C64.2589 15.1142 63.8833 15.4955 63.4236 15.7645C62.9639 16.0336 62.4313 16.1682 61.8258 16.1682C61.2204 16.1682 60.6598 16.0505 60.144 15.815C59.6283 15.5795 59.1854 15.2544 58.8154 14.8395C58.4454 14.4247 58.1539 13.9426 57.9408 13.3932C57.739 12.8326 57.6381 12.2327 57.6381 11.5936C57.6381 10.9545 57.7334 10.3603 57.924 9.81091C58.1258 9.26151 58.4005 8.77939 58.7481 8.36454C59.0957 7.9497 59.5105 7.62454 59.9927 7.38909C60.4748 7.15364 60.9961 7.03591 61.5568 7.03591C62.2183 7.03591 62.8069 7.19288 63.3227 7.50682C63.8384 7.82076 64.2477 8.23 64.5504 8.73455V3.72273H66.804V16H64.5504ZM64.5504 10.6686C64.3598 10.1641 64.0458 9.75485 63.6086 9.44091C63.1825 9.11576 62.734 8.95318 62.2631 8.95318C61.9268 8.95318 61.6184 9.03167 61.3381 9.18864C61.0578 9.33439 60.8168 9.53061 60.6149 9.77727C60.4131 10.0239 60.2561 10.3098 60.144 10.635C60.0319 10.9602 59.9758 11.2965 59.9758 11.6441C59.9758 12.0141 60.0375 12.3561 60.1608 12.67C60.2842 12.9839 60.4524 13.2586 60.6654 13.4941C60.8896 13.7295 61.1475 13.9145 61.439 14.0491C61.7305 14.1836 62.0501 14.2509 62.3977 14.2509C62.6219 14.2509 62.8461 14.2173 63.0704 14.15C63.2946 14.0715 63.5021 13.965 63.6927 13.8305C63.8945 13.6959 64.0683 13.5389 64.214 13.3595C64.371 13.1802 64.4831 12.9839 64.5504 12.7709V10.6686ZM72.9223 16.1682C72.2159 16.1682 71.5768 16.0505 71.005 15.815C70.4332 15.5683 69.9455 15.2376 69.5418 14.8227C69.1382 14.4079 68.8243 13.9258 68.6 13.3764C68.387 12.827 68.2805 12.2495 68.2805 11.6441C68.2805 11.0162 68.387 10.4276 68.6 9.87818C68.8131 9.31758 69.1214 8.82985 69.525 8.415C69.9287 7.98894 70.4164 7.65258 70.9882 7.40591C71.5712 7.15924 72.2215 7.03591 72.9391 7.03591C73.6567 7.03591 74.2958 7.15924 74.8564 7.40591C75.4282 7.65258 75.9103 7.98333 76.3028 8.39818C76.7064 8.81303 77.0091 9.29515 77.2109 9.84454C77.424 10.3939 77.5305 10.9658 77.5305 11.56C77.5305 11.7058 77.5249 11.8459 77.5137 11.9805C77.5137 12.115 77.5024 12.2271 77.48 12.3168H70.6687C70.7023 12.6644 70.7864 12.9727 70.9209 13.2418C71.0555 13.5109 71.2293 13.7408 71.4423 13.9314C71.6553 14.122 71.8964 14.2677 72.1655 14.3686C72.4346 14.4695 72.7149 14.52 73.0064 14.52C73.4549 14.52 73.8753 14.4135 74.2678 14.2005C74.6714 13.9762 74.9461 13.6847 75.0918 13.3259L77.0259 13.8641C76.7008 14.5368 76.1794 15.0918 75.4618 15.5291C74.7555 15.9552 73.909 16.1682 72.9223 16.1682ZM75.2096 10.8536C75.1535 10.1921 74.9068 9.66515 74.4696 9.27273C74.0435 8.86909 73.5221 8.66727 72.9055 8.66727C72.6028 8.66727 72.3168 8.72333 72.0478 8.83545C71.7899 8.93636 71.56 9.08212 71.3582 9.27273C71.1564 9.46333 70.9882 9.69318 70.8537 9.96227C70.7303 10.2314 70.6574 10.5285 70.635 10.8536H75.2096ZM84.1507 9.13818C83.4667 9.14939 82.8557 9.28394 82.3175 9.54182C81.7793 9.78848 81.3925 10.1641 81.157 10.6686V16H78.9034V7.18727H80.972V9.07091C81.129 8.76818 81.314 8.49909 81.527 8.26364C81.7401 8.01697 81.9699 7.80394 82.2166 7.62454C82.4632 7.44515 82.7099 7.31061 82.9566 7.22091C83.2145 7.12 83.4611 7.06955 83.6966 7.06955C83.8199 7.06955 83.9096 7.06955 83.9657 7.06955C84.0329 7.06955 84.0946 7.07515 84.1507 7.08636V9.13818ZM90.6742 16V14.7723C90.3378 15.2432 89.9117 15.5964 89.396 15.8318C88.8802 16.0561 88.314 16.1682 87.6973 16.1682C87.2713 16.1682 86.8732 16.1009 86.5032 15.9664C86.1332 15.8206 85.8137 15.6244 85.5446 15.3777C85.2755 15.1198 85.0625 14.8227 84.9055 14.4864C84.7598 14.15 84.6869 13.78 84.6869 13.3764C84.6869 12.9279 84.7878 12.5298 84.9896 12.1823C85.1914 11.8235 85.4661 11.5208 85.8137 11.2741C86.1613 11.0274 86.5593 10.8424 87.0078 10.7191C87.4563 10.5958 87.9328 10.5341 88.4373 10.5341C88.9082 10.5341 89.3287 10.5733 89.6987 10.6518C90.0687 10.7303 90.3658 10.82 90.5901 10.9209V10.4164C90.5901 9.84455 90.4219 9.40167 90.0855 9.08773C89.7604 8.76258 89.2726 8.6 88.6223 8.6C88.1514 8.6 87.6917 8.68409 87.2432 8.85227C86.7948 9.02045 86.3351 9.26712 85.8642 9.59227L85.1746 8.16273C85.7128 7.80394 86.2846 7.52924 86.8901 7.33864C87.5067 7.13682 88.157 7.03591 88.841 7.03591C90.1304 7.03591 91.117 7.35545 91.801 7.99455C92.4961 8.62242 92.8437 9.51379 92.8437 10.6686V16H90.6742ZM90.2201 13.78C90.4667 13.5894 90.5901 13.3764 90.5901 13.1409V12.1318C90.3098 12.0197 90.0126 11.9356 89.6987 11.8795C89.3848 11.8235 89.0876 11.7955 88.8073 11.7955C88.5607 11.7955 88.314 11.8235 88.0673 11.8795C87.8319 11.9356 87.6189 12.0253 87.4282 12.1486C87.2489 12.2608 87.1031 12.4065 86.991 12.5859C86.8789 12.7541 86.8228 12.9559 86.8228 13.1914C86.8228 13.5838 86.9685 13.9033 87.2601 14.15C87.5628 14.3967 87.9216 14.52 88.3364 14.52C88.6728 14.52 89.0148 14.4639 89.3623 14.3518C89.7211 14.2285 90.007 14.0379 90.2201 13.78ZM95.4429 16V9.22227H94.1311V7.18727H95.4429V4.32818H97.7638V7.18727H99.7988V9.22227H97.7638V16H95.4429ZM104.867 16.1682C104.161 16.1682 103.522 16.0505 102.95 15.815C102.378 15.5683 101.89 15.2376 101.487 14.8227C101.083 14.4079 100.769 13.9258 100.545 13.3764C100.332 12.827 100.225 12.2495 100.225 11.6441C100.225 11.0162 100.332 10.4276 100.545 9.87818C100.758 9.31758 101.066 8.82985 101.47 8.415C101.873 7.98894 102.361 7.65258 102.933 7.40591C103.516 7.15924 104.166 7.03591 104.884 7.03591C105.601 7.03591 106.24 7.15924 106.801 7.40591C107.373 7.65258 107.855 7.98333 108.247 8.39818C108.651 8.81303 108.954 9.29515 109.156 9.84454C109.369 10.3939 109.475 10.9658 109.475 11.56C109.475 11.7058 109.47 11.8459 109.458 11.9805C109.458 12.115 109.447 12.2271 109.425 12.3168H102.613C102.647 12.6644 102.731 12.9727 102.866 13.2418C103 13.5109 103.174 13.7408 103.387 13.9314C103.6 14.122 103.841 14.2677 104.11 14.3686C104.379 14.4695 104.66 14.52 104.951 14.52C105.4 14.52 105.82 14.4135 106.212 14.2005C106.616 13.9762 106.891 13.6847 107.037 13.3259L108.971 13.8641C108.645 14.5368 108.124 15.0918 107.407 15.5291C106.7 15.9552 105.854 16.1682 104.867 16.1682ZM107.154 10.8536C107.098 10.1921 106.852 9.66515 106.414 9.27273C105.988 8.86909 105.467 8.66727 104.85 8.66727C104.547 8.66727 104.262 8.72333 103.992 8.83545C103.735 8.93636 103.505 9.08212 103.303 9.27273C103.101 9.46333 102.933 9.69318 102.798 9.96227C102.675 10.2314 102.602 10.5285 102.58 10.8536H107.154ZM117.222 16V14.6209C116.931 15.1142 116.555 15.4955 116.095 15.7645C115.636 16.0336 115.103 16.1682 114.498 16.1682C113.892 16.1682 113.332 16.0505 112.816 15.815C112.3 15.5795 111.857 15.2544 111.487 14.8395C111.117 14.4247 110.826 13.9426 110.613 13.3932C110.411 12.8326 110.31 12.2327 110.31 11.5936C110.31 10.9545 110.405 10.3603 110.596 9.81091C110.798 9.26151 111.072 8.77939 111.42 8.36454C111.767 7.9497 112.182 7.62454 112.664 7.38909C113.147 7.15364 113.668 7.03591 114.229 7.03591C114.89 7.03591 115.479 7.19288 115.994 7.50682C116.51 7.82076 116.919 8.23 117.222 8.73455V3.72273H119.476V16H117.222ZM117.222 10.6686C117.032 10.1641 116.718 9.75485 116.28 9.44091C115.854 9.11576 115.406 8.95318 114.935 8.95318C114.599 8.95318 114.29 9.03167 114.01 9.18864C113.73 9.33439 113.489 9.53061 113.287 9.77727C113.085 10.0239 112.928 10.3098 112.816 10.635C112.704 10.9602 112.648 11.2965 112.648 11.6441C112.648 12.0141 112.709 12.3561 112.833 12.67C112.956 12.9839 113.124 13.2586 113.337 13.4941C113.561 13.7295 113.819 13.9145 114.111 14.0491C114.402 14.1836 114.722 14.2509 115.069 14.2509C115.294 14.2509 115.518 14.2173 115.742 14.15C115.966 14.0715 116.174 13.965 116.364 13.8305C116.566 13.6959 116.74 13.5389 116.886 13.3595C117.043 13.1802 117.155 12.9839 117.222 12.7709V10.6686ZM125.766 16V4.05909H130.828C131.378 4.05909 131.882 4.17682 132.342 4.41227C132.813 4.63651 133.217 4.93924 133.553 5.32045C133.889 5.69045 134.153 6.11651 134.343 6.59864C134.534 7.06955 134.629 7.54606 134.629 8.02818C134.629 8.53273 134.54 9.02606 134.36 9.50818C134.181 9.97909 133.929 10.3995 133.603 10.7695C133.278 11.1395 132.886 11.4367 132.426 11.6609C131.967 11.8852 131.462 11.9973 130.913 11.9973H128.087V16H125.766ZM128.087 9.96227H130.778C131.204 9.96227 131.557 9.78848 131.838 9.44091C132.129 9.09333 132.275 8.62242 132.275 8.02818C132.275 7.72545 132.23 7.45636 132.14 7.22091C132.051 6.97424 131.933 6.76682 131.787 6.59864C131.641 6.43045 131.468 6.30712 131.266 6.22864C131.075 6.13894 130.879 6.09409 130.677 6.09409H128.087V9.96227ZM139.965 16.1682C139.259 16.1682 138.62 16.0505 138.048 15.815C137.476 15.5683 136.988 15.2376 136.585 14.8227C136.181 14.4079 135.867 13.9258 135.643 13.3764C135.43 12.827 135.323 12.2495 135.323 11.6441C135.323 11.0162 135.43 10.4276 135.643 9.87818C135.856 9.31758 136.164 8.82985 136.568 8.415C136.971 7.98894 137.459 7.65258 138.031 7.40591C138.614 7.15924 139.264 7.03591 139.982 7.03591C140.699 7.03591 141.339 7.15924 141.899 7.40591C142.471 7.65258 142.953 7.98333 143.346 8.39818C143.749 8.81303 144.052 9.29515 144.254 9.84454C144.467 10.3939 144.573 10.9658 144.573 11.56C144.573 11.7058 144.568 11.8459 144.556 11.9805C144.556 12.115 144.545 12.2271 144.523 12.3168H137.711C137.745 12.6644 137.829 12.9727 137.964 13.2418C138.098 13.5109 138.272 13.7408 138.485 13.9314C138.698 14.122 138.939 14.2677 139.208 14.3686C139.477 14.4695 139.758 14.52 140.049 14.52C140.498 14.52 140.918 14.4135 141.311 14.2005C141.714 13.9762 141.989 13.6847 142.135 13.3259L144.069 13.8641C143.744 14.5368 143.222 15.0918 142.505 15.5291C141.798 15.9552 140.952 16.1682 139.965 16.1682ZM142.252 10.8536C142.196 10.1921 141.95 9.66515 141.512 9.27273C141.086 8.86909 140.565 8.66727 139.948 8.66727C139.646 8.66727 139.36 8.72333 139.091 8.83545C138.833 8.93636 138.603 9.08212 138.401 9.27273C138.199 9.46333 138.031 9.69318 137.896 9.96227C137.773 10.2314 137.7 10.5285 137.678 10.8536H142.252ZM151.193 9.13818C150.51 9.14939 149.898 9.28394 149.36 9.54182C148.822 9.78848 148.435 10.1641 148.2 10.6686V16H145.946V7.18727H148.015V9.07091C148.172 8.76818 148.357 8.49909 148.57 8.26364C148.783 8.01697 149.013 7.80394 149.259 7.62454C149.506 7.44515 149.753 7.31061 149.999 7.22091C150.257 7.12 150.504 7.06955 150.739 7.06955C150.863 7.06955 150.952 7.06955 151.008 7.06955C151.076 7.06955 151.137 7.07515 151.193 7.08636V9.13818ZM155.78 16.1682C155.04 16.1682 154.317 16.0505 153.611 15.815C152.904 15.5795 152.299 15.2432 151.794 14.8059L152.635 13.3932C153.173 13.7744 153.695 14.0659 154.199 14.2677C154.715 14.4583 155.225 14.5536 155.73 14.5536C156.178 14.5536 156.531 14.4695 156.789 14.3014C157.047 14.1332 157.176 13.8921 157.176 13.5782C157.176 13.2642 157.025 13.0344 156.722 12.8886C156.419 12.7429 155.926 12.5747 155.242 12.3841C154.67 12.2271 154.182 12.0758 153.779 11.93C153.375 11.7842 153.05 11.6217 152.803 11.4423C152.557 11.2517 152.377 11.0386 152.265 10.8032C152.153 10.5565 152.097 10.265 152.097 9.92864C152.097 9.48015 152.181 9.07651 152.349 8.71773C152.529 8.35894 152.775 8.05621 153.089 7.80955C153.403 7.55167 153.768 7.35545 154.182 7.22091C154.608 7.08636 155.068 7.01909 155.561 7.01909C156.223 7.01909 156.84 7.11439 157.411 7.305C157.994 7.49561 158.527 7.80394 159.009 8.23L158.101 9.59227C157.653 9.25591 157.215 9.00924 156.789 8.85227C156.374 8.6953 155.959 8.61682 155.545 8.61682C155.163 8.61682 154.844 8.6953 154.586 8.85227C154.328 9.00924 154.199 9.26151 154.199 9.60909C154.199 9.76606 154.227 9.895 154.283 9.99591C154.351 10.0968 154.451 10.1865 154.586 10.265C154.721 10.3435 154.894 10.422 155.107 10.5005C155.332 10.5677 155.606 10.6406 155.931 10.7191C156.537 10.8761 157.053 11.033 157.479 11.19C157.916 11.347 158.269 11.5264 158.538 11.7282C158.819 11.93 159.02 12.1655 159.144 12.4345C159.278 12.6924 159.346 13.0064 159.346 13.3764C159.346 14.2397 159.026 14.9236 158.387 15.4282C157.748 15.9215 156.879 16.1682 155.78 16.1682ZM164.88 16.1682C164.162 16.1682 163.518 16.0448 162.946 15.7982C162.374 15.5515 161.886 15.2208 161.483 14.8059C161.09 14.3798 160.787 13.8921 160.574 13.3427C160.361 12.7933 160.255 12.2159 160.255 11.6105C160.255 10.9938 160.361 10.4108 160.574 9.86136C160.787 9.31197 161.09 8.82985 161.483 8.415C161.886 7.98894 162.374 7.65258 162.946 7.40591C163.518 7.15924 164.162 7.03591 164.88 7.03591C165.597 7.03591 166.237 7.15924 166.797 7.40591C167.369 7.65258 167.851 7.98894 168.244 8.415C168.647 8.82985 168.956 9.31197 169.169 9.86136C169.382 10.4108 169.488 10.9938 169.488 11.6105C169.488 12.2159 169.382 12.7933 169.169 13.3427C168.956 13.8921 168.653 14.3798 168.26 14.8059C167.868 15.2208 167.386 15.5515 166.814 15.7982C166.242 16.0448 165.597 16.1682 164.88 16.1682ZM162.576 11.6105C162.576 12.0029 162.632 12.3617 162.744 12.6868C162.867 13.0008 163.03 13.2755 163.232 13.5109C163.445 13.7464 163.691 13.9314 163.972 14.0659C164.252 14.1892 164.555 14.2509 164.88 14.2509C165.205 14.2509 165.508 14.1892 165.788 14.0659C166.068 13.9314 166.309 13.7464 166.511 13.5109C166.724 13.2755 166.887 12.9952 166.999 12.67C167.122 12.3448 167.184 11.9861 167.184 11.5936C167.184 11.2124 167.122 10.8592 166.999 10.5341C166.887 10.2089 166.724 9.92864 166.511 9.69318C166.309 9.45773 166.068 9.27833 165.788 9.155C165.508 9.02045 165.205 8.95318 164.88 8.95318C164.555 8.95318 164.252 9.02045 163.972 9.155C163.691 9.28955 163.445 9.47455 163.232 9.71C163.03 9.94545 162.867 10.2258 162.744 10.5509C162.632 10.8761 162.576 11.2292 162.576 11.6105ZM179.2 16H176.946V11.0555C176.946 10.3491 176.823 9.83333 176.576 9.50818C176.329 9.18303 175.987 9.02045 175.55 9.02045C175.326 9.02045 175.096 9.0653 174.861 9.155C174.625 9.2447 174.401 9.37364 174.188 9.54182C173.986 9.69879 173.801 9.88939 173.633 10.1136C173.465 10.3379 173.341 10.5845 173.263 10.8536V16H171.009V7.18727H173.044V8.81864C173.369 8.25803 173.84 7.82076 174.457 7.50682C175.074 7.19288 175.769 7.03591 176.542 7.03591C177.092 7.03591 177.54 7.13682 177.888 7.33864C178.235 7.54045 178.505 7.80394 178.695 8.12909C178.886 8.45424 179.015 8.82424 179.082 9.23909C179.16 9.65394 179.2 10.0744 179.2 10.5005V16ZM186.541 16V14.7723C186.205 15.2432 185.779 15.5964 185.263 15.8318C184.747 16.0561 184.181 16.1682 183.564 16.1682C183.138 16.1682 182.74 16.1009 182.37 15.9664C182 15.8206 181.681 15.6244 181.412 15.3777C181.142 15.1198 180.929 14.8227 180.772 14.4864C180.627 14.15 180.554 13.78 180.554 13.3764C180.554 12.9279 180.655 12.5298 180.857 12.1823C181.058 11.8235 181.333 11.5208 181.681 11.2741C182.028 11.0274 182.426 10.8424 182.875 10.7191C183.323 10.5958 183.8 10.5341 184.304 10.5341C184.775 10.5341 185.196 10.5733 185.566 10.6518C185.936 10.7303 186.233 10.82 186.457 10.9209V10.4164C186.457 9.84455 186.289 9.40167 185.952 9.08773C185.627 8.76258 185.14 8.6 184.489 8.6C184.018 8.6 183.559 8.68409 183.11 8.85227C182.662 9.02045 182.202 9.26712 181.731 9.59227L181.042 8.16273C181.58 7.80394 182.152 7.52924 182.757 7.33864C183.374 7.13682 184.024 7.03591 184.708 7.03591C185.997 7.03591 186.984 7.35545 187.668 7.99455C188.363 8.62242 188.711 9.51379 188.711 10.6686V16H186.541ZM186.087 13.78C186.334 13.5894 186.457 13.3764 186.457 13.1409V12.1318C186.177 12.0197 185.88 11.9356 185.566 11.8795C185.252 11.8235 184.955 11.7955 184.674 11.7955C184.428 11.7955 184.181 11.8235 183.934 11.8795C183.699 11.9356 183.486 12.0253 183.295 12.1486C183.116 12.2608 182.97 12.4065 182.858 12.5859C182.746 12.7541 182.69 12.9559 182.69 13.1914C182.69 13.5838 182.835 13.9033 183.127 14.15C183.43 14.3967 183.788 14.52 184.203 14.52C184.54 14.52 184.882 14.4639 185.229 14.3518C185.588 14.2285 185.874 14.0379 186.087 13.78ZM190.702 3.72273H192.956V16H190.702V3.72273Z" fill="#4859B2"/>
+<path d="M39.281 31.5044V20.8041H43.742C44.2142 20.8041 44.6462 20.9046 45.0381 21.1055C45.44 21.2964 45.7816 21.5576 46.0629 21.8892C46.3543 22.2107 46.5803 22.5774 46.7411 22.9894C46.9018 23.3913 46.9822 23.8032 46.9822 24.2252C46.9822 24.6673 46.9069 25.0943 46.7562 25.5062C46.6054 25.9181 46.3894 26.2849 46.1081 26.6064C45.8368 26.9279 45.5053 27.1841 45.1134 27.375C44.7316 27.5659 44.3046 27.6613 43.8324 27.6613H40.6374V31.5044H39.281ZM40.6374 26.4557H43.7571C44.0384 26.4557 44.2896 26.4004 44.5106 26.2899C44.7417 26.1693 44.9376 26.0086 45.0984 25.8076C45.2591 25.5966 45.3847 25.3555 45.4751 25.0842C45.5656 24.8129 45.6108 24.5266 45.6108 24.2252C45.6108 23.9137 45.5555 23.6223 45.445 23.3511C45.3445 23.0798 45.2039 22.8437 45.023 22.6427C44.8522 22.4418 44.6462 22.2861 44.4051 22.1755C44.174 22.065 43.9279 22.0098 43.6666 22.0098H40.6374V26.4557ZM52.6194 24.7979C51.9563 24.818 51.3685 24.9888 50.8561 25.3103C50.3538 25.6318 49.9971 26.0789 49.7861 26.6516V31.5044H48.4599V23.6374H49.6957V25.461C49.967 24.9184 50.3236 24.4814 50.7657 24.1498C51.2078 23.8082 51.68 23.6173 52.1824 23.5771C52.2828 23.5771 52.3682 23.5771 52.4386 23.5771C52.5089 23.5771 52.5692 23.5822 52.6194 23.5922V24.7979ZM57.1944 31.6551C56.6016 31.6551 56.059 31.5446 55.5667 31.3235C55.0844 31.1025 54.6675 30.8061 54.3158 30.4344C53.9742 30.0626 53.708 29.6306 53.5171 29.1383C53.3262 28.646 53.2307 28.1285 53.2307 27.586C53.2307 27.0334 53.3262 26.5109 53.5171 26.0186C53.718 25.5263 53.9893 25.0943 54.3309 24.7225C54.6826 24.3508 55.0995 24.0544 55.5818 23.8333C56.0741 23.6123 56.6116 23.5018 57.1944 23.5018C57.7771 23.5018 58.3146 23.6123 58.8069 23.8333C59.2993 24.0544 59.7162 24.3508 60.0578 24.7225C60.4095 25.0943 60.6807 25.5263 60.8716 26.0186C61.0726 26.5109 61.1731 27.0334 61.1731 27.586C61.1731 28.1285 61.0776 28.646 60.8867 29.1383C60.6958 29.6306 60.4245 30.0626 60.0729 30.4344C59.7212 30.8061 59.2993 31.1025 58.8069 31.3235C58.3247 31.5446 57.7871 31.6551 57.1944 31.6551ZM54.5871 27.601C54.5871 28.013 54.6524 28.3948 54.783 28.7464C54.9237 29.0981 55.1096 29.4045 55.3406 29.6658C55.5818 29.927 55.8581 30.1329 56.1695 30.2837C56.4911 30.4344 56.8327 30.5097 57.1944 30.5097C57.5561 30.5097 57.8926 30.4344 58.2041 30.2837C58.5256 30.1329 58.8069 29.927 59.0481 29.6658C59.2892 29.3945 59.4751 29.083 59.6057 28.7314C59.7464 28.3697 59.8167 27.9828 59.8167 27.5709C59.8167 27.169 59.7464 26.7922 59.6057 26.4406C59.4751 26.0789 59.2892 25.7674 59.0481 25.5062C58.8069 25.2349 58.5256 25.0239 58.2041 24.8732C57.8926 24.7225 57.5561 24.6472 57.1944 24.6472C56.8327 24.6472 56.4911 24.7275 56.1695 24.8883C55.8581 25.039 55.5818 25.25 55.3406 25.5213C55.1096 25.7825 54.9237 26.094 54.783 26.4557C54.6524 26.8073 54.5871 27.1891 54.5871 27.601ZM63.0696 31.5044V24.6773H61.9996V23.6374H63.0696V23.4716C63.0696 22.4971 63.2856 21.7335 63.7177 21.1809C64.1497 20.6283 64.7375 20.352 65.481 20.352C65.7924 20.352 66.0989 20.3972 66.4003 20.4876C66.7017 20.568 66.973 20.6835 67.2141 20.8342L66.8826 21.8138C66.7419 21.7134 66.5661 21.633 66.3551 21.5727C66.1541 21.5124 65.9532 21.4823 65.7522 21.4823C65.3102 21.4823 64.9736 21.6481 64.7425 21.9796C64.5114 22.3112 64.3959 22.7934 64.3959 23.4264V23.6374H66.4907V24.6773H64.3959V31.5044H63.0696ZM67.8135 31.5044V23.6374H69.1398V31.5044H67.8135ZM67.8135 22.1605V20.5027H69.1398V22.1605H67.8135ZM71.3622 20.5027H72.6885V31.5044H71.3622V20.5027ZM78.3888 31.6551C77.796 31.6551 77.2534 31.5496 76.7611 31.3386C76.2688 31.1176 75.8468 30.8212 75.4952 30.4494C75.1435 30.0777 74.8672 29.6457 74.6663 29.1533C74.4754 28.651 74.3799 28.1235 74.3799 27.5709C74.3799 27.0183 74.4754 26.4959 74.6663 26.0035C74.8672 25.5112 75.1435 25.0792 75.4952 24.7074C75.8569 24.3357 76.2839 24.0443 76.7762 23.8333C77.2685 23.6123 77.8111 23.5018 78.4039 23.5018C78.9966 23.5018 79.5342 23.6123 80.0164 23.8333C80.5087 24.0544 80.9257 24.3508 81.2673 24.7225C81.6089 25.0842 81.8701 25.5112 82.051 26.0035C82.2419 26.4858 82.3373 26.9882 82.3373 27.5106C82.3373 27.6211 82.3323 27.7216 82.3223 27.812C82.3223 27.9025 82.3172 27.9728 82.3072 28.023H75.7815C75.8117 28.4149 75.9021 28.7715 76.0528 29.0931C76.2035 29.4146 76.3994 29.6909 76.6406 29.922C76.8817 30.153 77.153 30.3339 77.4544 30.4645C77.7659 30.5951 78.0924 30.6604 78.434 30.6604C78.6751 30.6604 78.9112 30.6303 79.1423 30.57C79.3734 30.4997 79.5894 30.4092 79.7904 30.2987C79.9913 30.1882 80.1671 30.0526 80.3179 29.8918C80.4786 29.7311 80.5992 29.5502 80.6796 29.3493L81.8249 29.6658C81.6943 29.9571 81.5135 30.2234 81.2824 30.4645C81.0613 30.7056 80.8001 30.9166 80.4987 31.0975C80.2073 31.2683 79.8808 31.4039 79.5191 31.5044C79.1574 31.6049 78.7806 31.6551 78.3888 31.6551ZM81.0865 27.0434C81.0563 26.6717 80.9609 26.3301 80.8001 26.0186C80.6494 25.6971 80.4535 25.4258 80.2124 25.2048C79.9813 24.9837 79.71 24.8129 79.3985 24.6924C79.0871 24.5618 78.7555 24.4965 78.4039 24.4965C78.0522 24.4965 77.7206 24.5618 77.4092 24.6924C77.0977 24.8129 76.8214 24.9888 76.5803 25.2199C76.3492 25.4409 76.1583 25.7071 76.0076 26.0186C75.8669 26.3301 75.7815 26.6717 75.7514 27.0434H81.0865ZM87.8344 31.5044V20.8041H92.2954C92.7676 20.8041 93.1997 20.9046 93.5915 21.1055C93.9934 21.2964 94.335 21.5576 94.6163 21.8892C94.9077 22.2107 95.1337 22.5774 95.2945 22.9894C95.4553 23.3913 95.5356 23.8032 95.5356 24.2252C95.5356 24.6673 95.4603 25.0943 95.3096 25.5062C95.1589 25.9181 94.9428 26.2849 94.6615 26.6064C94.3902 26.9279 94.0587 27.1841 93.6668 27.375C93.2851 27.5659 92.858 27.6613 92.3858 27.6613H89.1908V31.5044H87.8344ZM89.1908 26.4557H92.3105C92.5918 26.4557 92.843 26.4004 93.064 26.2899C93.2951 26.1693 93.491 26.0086 93.6518 25.8076C93.8125 25.5966 93.9381 25.3555 94.0285 25.0842C94.119 24.8129 94.1642 24.5266 94.1642 24.2252C94.1642 23.9137 94.1089 23.6223 93.9984 23.3511C93.8979 23.0798 93.7573 22.8437 93.5764 22.6427C93.4056 22.4418 93.1997 22.2861 92.9585 22.1755C92.7274 22.065 92.4813 22.0098 92.22 22.0098H89.1908V26.4557ZM101.868 31.5044V30.3138C101.527 30.776 101.095 31.1176 100.572 31.3386C100.06 31.5496 99.5172 31.6551 98.9445 31.6551C98.5727 31.6551 98.2261 31.5948 97.9046 31.4743C97.5831 31.3436 97.3017 31.1678 97.0606 30.9468C96.8295 30.7257 96.6437 30.4695 96.503 30.1782C96.3724 29.8767 96.3071 29.5502 96.3071 29.1986C96.3071 28.7866 96.4025 28.4299 96.5934 28.1285C96.7843 27.8171 97.0355 27.5609 97.347 27.3599C97.6685 27.159 98.0251 27.0133 98.417 26.9229C98.8088 26.8224 99.2107 26.7722 99.6227 26.7722C100.135 26.7722 100.577 26.8174 100.949 26.9078C101.331 26.9882 101.622 27.0736 101.823 27.164V26.531C101.823 25.898 101.642 25.3957 101.28 25.0239C100.919 24.6522 100.406 24.4663 99.7432 24.4663C98.9495 24.4663 98.1156 24.7728 97.2415 25.3856L96.8044 24.5266C97.2565 24.2252 97.7338 23.979 98.2361 23.7881C98.7485 23.5972 99.2911 23.5018 99.8638 23.5018C100.396 23.5018 100.863 23.5771 101.265 23.7278C101.677 23.8785 102.024 24.0946 102.305 24.3759C102.587 24.6472 102.798 24.9787 102.938 25.3706C103.079 25.7624 103.149 26.1944 103.149 26.6667V31.5044H101.868ZM101.537 29.6959C101.728 29.4849 101.823 29.289 101.823 29.1081V27.9477C101.501 27.8171 101.165 27.7216 100.813 27.6613C100.472 27.601 100.14 27.5709 99.8186 27.5709C99.5573 27.5709 99.2911 27.601 99.0198 27.6613C98.7586 27.7116 98.5175 27.802 98.2964 27.9326C98.0854 28.0532 97.9096 28.2089 97.7689 28.3998C97.6383 28.5907 97.573 28.8218 97.573 29.0931C97.573 29.3241 97.6182 29.5402 97.7087 29.7411C97.7991 29.932 97.9247 30.0978 98.0854 30.2384C98.2462 30.3691 98.427 30.4746 98.628 30.5549C98.839 30.6253 99.06 30.6604 99.2911 30.6604C99.492 30.6604 99.698 30.6403 99.909 30.6001C100.13 30.56 100.341 30.5047 100.542 30.4344C100.743 30.354 100.929 30.2535 101.1 30.1329C101.27 30.0124 101.416 29.8667 101.537 29.6959ZM108.331 31.5948C107.799 31.5948 107.306 31.4843 106.854 31.2633C106.412 31.0422 106.03 30.7458 105.709 30.3741C105.387 30.0023 105.136 29.5753 104.955 29.0931C104.784 28.6108 104.699 28.1084 104.699 27.586C104.699 27.0334 104.784 26.5109 104.955 26.0186C105.136 25.5162 105.387 25.0792 105.709 24.7074C106.03 24.3357 106.412 24.0443 106.854 23.8333C107.306 23.6123 107.804 23.5018 108.346 23.5018C109.009 23.5018 109.582 23.6625 110.064 23.984C110.546 24.3056 110.953 24.7125 111.285 25.2048V23.6374H112.46V31.414C112.46 31.9766 112.355 32.4689 112.144 32.8909C111.933 33.3229 111.647 33.6846 111.285 33.976C110.923 34.2674 110.496 34.4884 110.004 34.6391C109.522 34.7898 109.004 34.8652 108.452 34.8652C107.557 34.8652 106.829 34.7095 106.266 34.398C105.714 34.0966 105.252 33.6746 104.88 33.132L105.648 32.4539C105.96 32.916 106.362 33.2627 106.854 33.4937C107.346 33.7248 107.879 33.8404 108.452 33.8404C108.813 33.8404 109.155 33.7901 109.476 33.6897C109.808 33.5892 110.094 33.4385 110.335 33.2375C110.577 33.0366 110.767 32.7854 110.908 32.484C111.059 32.1826 111.134 31.8259 111.134 31.414V30.0275C110.983 30.2686 110.803 30.4896 110.592 30.6906C110.391 30.8815 110.17 31.0472 109.929 31.1879C109.687 31.3185 109.431 31.419 109.16 31.4893C108.889 31.5597 108.612 31.5948 108.331 31.5948ZM108.738 30.5097C109.019 30.5097 109.291 30.4595 109.552 30.359C109.813 30.2585 110.054 30.1279 110.275 29.9672C110.496 29.7964 110.682 29.6055 110.833 29.3945C110.983 29.1835 111.084 28.9675 111.134 28.7464V26.4858C111.024 26.2145 110.878 25.9684 110.697 25.7473C110.526 25.5263 110.33 25.3354 110.109 25.1746C109.888 25.0038 109.647 24.8732 109.386 24.7828C109.135 24.6924 108.879 24.6472 108.617 24.6472C108.215 24.6472 107.854 24.7326 107.532 24.9034C107.221 25.0742 106.955 25.3002 106.733 25.5816C106.512 25.8629 106.342 26.1844 106.221 26.5461C106.101 26.8977 106.04 27.2544 106.04 27.6161C106.04 28.008 106.111 28.3797 106.251 28.7314C106.392 29.083 106.583 29.3895 106.824 29.6507C107.065 29.9119 107.346 30.1229 107.668 30.2837C107.999 30.4344 108.356 30.5097 108.738 30.5097ZM118.082 31.6551C117.489 31.6551 116.947 31.5496 116.455 31.3386C115.962 31.1176 115.54 30.8212 115.189 30.4494C114.837 30.0777 114.561 29.6457 114.36 29.1533C114.169 28.651 114.073 28.1235 114.073 27.5709C114.073 27.0183 114.169 26.4959 114.36 26.0035C114.561 25.5112 114.837 25.0792 115.189 24.7074C115.55 24.3357 115.977 24.0443 116.47 23.8333C116.962 23.6123 117.504 23.5018 118.097 23.5018C118.69 23.5018 119.228 23.6123 119.71 23.8333C120.202 24.0544 120.619 24.3508 120.961 24.7225C121.302 25.0842 121.564 25.5112 121.744 26.0035C121.935 26.4858 122.031 26.9882 122.031 27.5106C122.031 27.6211 122.026 27.7216 122.016 27.812C122.016 27.9025 122.011 27.9728 122.001 28.023H115.475C115.505 28.4149 115.596 28.7715 115.746 29.0931C115.897 29.4146 116.093 29.6909 116.334 29.922C116.575 30.153 116.846 30.3339 117.148 30.4645C117.459 30.5951 117.786 30.6604 118.127 30.6604C118.369 30.6604 118.605 30.6303 118.836 30.57C119.067 30.4997 119.283 30.4092 119.484 30.2987C119.685 30.1882 119.861 30.0526 120.011 29.8918C120.172 29.7311 120.293 29.5502 120.373 29.3493L121.518 29.6658C121.388 29.9571 121.207 30.2234 120.976 30.4645C120.755 30.7056 120.494 30.9166 120.192 31.0975C119.901 31.2683 119.574 31.4039 119.213 31.5044C118.851 31.6049 118.474 31.6551 118.082 31.6551ZM120.78 27.0434C120.75 26.6717 120.654 26.3301 120.494 26.0186C120.343 25.6971 120.147 25.4258 119.906 25.2048C119.675 24.9837 119.403 24.8129 119.092 24.6924C118.78 24.5618 118.449 24.4965 118.097 24.4965C117.746 24.4965 117.414 24.5618 117.103 24.6924C116.791 24.8129 116.515 24.9888 116.274 25.2199C116.043 25.4409 115.852 25.7071 115.701 26.0186C115.56 26.3301 115.475 26.6717 115.445 27.0434H120.78Z" fill="#4859B2"/>
+<mask id="mask0_239_6997" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="1" width="33" height="33">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M16.0537 1.9751H3.27627C1.46684 1.9751 0 3.44193 0 5.25137V17.828V30.4047C0 32.2141 1.46684 33.681 3.27627 33.681H16.0537H28.8312C30.6406 33.681 32.1074 32.2141 32.1074 30.4047V17.828V5.25137C32.1074 3.44193 30.6406 1.9751 28.8312 1.9751H16.0537ZM16.0537 1.9751C24.9199 1.9751 32.1074 9.0727 32.1074 17.828C32.1074 26.5834 24.9199 33.681 16.0537 33.681C7.18749 33.681 0 26.5834 0 17.828C0 9.0727 7.18749 1.9751 16.0537 1.9751Z" fill="#D9D9D9"/>
+<path d="M32.1074 17.828C32.1074 26.5834 24.9199 33.681 16.0537 33.681C7.18749 33.681 0 26.5834 0 17.828C0 9.0727 7.18749 1.9751 16.0537 1.9751C24.9199 1.9751 32.1074 9.0727 32.1074 17.828ZM2.29328 17.828C2.29328 25.3327 8.45404 31.4164 16.0537 31.4164C23.6534 31.4164 29.8142 25.3327 29.8142 17.828C29.8142 10.3234 23.6534 4.2397 16.0537 4.2397C8.45404 4.2397 2.29328 10.3234 2.29328 17.828Z" fill="#D9D9D9"/>
+<path d="M6.22656 14.916H12.0146C12.0146 14.916 13.4344 16.4258 16.1646 16.5337C18.6764 16.4258 20.0961 14.916 20.0961 14.916H25.8842V27.4258C18.3422 33.8035 13.2159 33.5729 6.22656 27.4258V14.916Z" fill="#D9D9D9" stroke="black" stroke-width="0.218418"/>
+<ellipse cx="16.055" cy="10.7104" rx="4.9144" ry="4.85294" fill="#D9D9D9"/>
+</mask>
+<g mask="url(#mask0_239_6997)">
+<rect y="1.9751" width="5.29244" height="5.22624" fill="#EF883B"/>
+<rect x="6.70312" y="1.9751" width="5.29244" height="5.22624" fill="#EF883B"/>
+<rect x="13.3242" y="1.9751" width="5.46045" height="3.23529" fill="#EF883B"/>
+<rect x="20.1094" y="1.9751" width="5.29244" height="5.22624" fill="#EF883B"/>
+<rect x="26.8164" y="1.9751" width="5.29244" height="5.22624" fill="#EF883B"/>
+<rect y="8.59521" width="5.29244" height="5.22624" fill="#EF883B"/>
+<rect x="6.76953" y="8.66162" width="3.93152" height="5.17647" fill="#EF883B"/>
+<rect x="12.2305" y="7.58301" width="7.64463" height="7.54902" rx="3.77451" fill="#4859B2"/>
+<rect x="21.625" y="8.66162" width="3.7131" height="5.17647" fill="#EF883B"/>
+<rect x="26.8164" y="8.59473" width="5.29244" height="5.22624" fill="#EF883B"/>
+<rect y="15.2148" width="5.29244" height="5.22624" fill="#EF883B"/>
+<path d="M6.70312 18.4911C6.70312 16.6817 8.16996 15.2148 9.97939 15.2148H11.9956V20.4411H6.70312V18.4911Z" fill="#4859B2"/>
+<rect x="13.3242" y="15.5635" width="5.46045" height="4.96078" fill="#4859B2"/>
+<path d="M20.1094 15.2148H22.1255C23.935 15.2148 25.4018 16.6817 25.4018 18.4911V20.4411H20.1094V15.2148Z" fill="#4859B2"/>
+<rect x="26.8164" y="15.2148" width="5.29244" height="5.22624" fill="#EF883B"/>
+<rect y="21.835" width="5.29244" height="5.22624" fill="#EF883B"/>
+<rect x="6.70312" y="21.835" width="5.29244" height="5.22624" fill="#4859B2"/>
+<rect x="13.4062" y="21.835" width="5.29244" height="5.22624" fill="#4859B2"/>
+<rect x="20.1094" y="21.835" width="5.29244" height="5.22624" fill="#4859B2"/>
+<rect x="26.8164" y="21.835" width="5.29244" height="5.22624" fill="#EF883B"/>
+<rect y="28.4546" width="5.29244" height="5.22624" fill="#4859B2"/>
+<rect x="6.70312" y="28.4546" width="5.29244" height="5.22624" fill="#4859B2"/>
+<rect x="13.4062" y="28.4546" width="5.29244" height="5.22624" fill="#4859B2"/>
+<rect x="20.1094" y="28.4546" width="5.29244" height="5.22624" fill="#4859B2"/>
+<rect x="26.8164" y="28.4546" width="5.29244" height="5.22624" fill="#4859B2"/>
+</g>
+</svg>
diff --git a/www/assets/css/src/icons/i.svg b/www/assets/css/src/icons/i.svg
new file mode 100644
index 0000000..464804d
--- /dev/null
+++ b/www/assets/css/src/icons/i.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M11.416 17.542H12.7285V10.8337H11.416V17.542ZM11.9993 8.96699C12.2132 8.96699 12.398 8.89407 12.5535 8.74824C12.7091 8.60241 12.7868 8.41283 12.7868 8.17949C12.7868 7.94616 12.7139 7.75658 12.5681 7.61074C12.4223 7.46491 12.2327 7.39199 11.9993 7.39199C11.766 7.39199 11.5764 7.46491 11.4306 7.61074C11.2848 7.75658 11.2118 7.94616 11.2118 8.17949C11.2118 8.41283 11.2848 8.60241 11.4306 8.74824C11.5764 8.89407 11.766 8.96699 11.9993 8.96699ZM11.9993 23.0837C10.4632 23.0837 9.02435 22.792 7.68268 22.2087C6.34102 21.6253 5.16949 20.833 4.1681 19.8316C3.16671 18.8302 2.37435 17.6587 1.79102 16.317C1.20768 14.9753 0.916016 13.5364 0.916016 12.0003C0.916016 10.4642 1.20768 9.02046 1.79102 7.66908C2.37435 6.31769 3.16671 5.14616 4.1681 4.15449C5.16949 3.16283 6.34102 2.37533 7.68268 1.79199C9.02435 1.20866 10.4632 0.916992 11.9993 0.916992C13.5355 0.916992 14.9792 1.20866 16.3306 1.79199C17.682 2.37533 18.8535 3.16283 19.8452 4.15449C20.8368 5.14616 21.6243 6.31769 22.2077 7.66908C22.791 9.02046 23.0827 10.4642 23.0827 12.0003C23.0827 13.5364 22.791 14.9753 22.2077 16.317C21.6243 17.6587 20.8368 18.8302 19.8452 19.8316C18.8535 20.833 17.682 21.6253 16.3306 22.2087C14.9792 22.792 13.5355 23.0837 11.9993 23.0837ZM12.0285 21.7712C14.7313 21.7712 17.0306 20.8184 18.9264 18.9128C20.8223 17.0073 21.7702 14.6934 21.7702 11.9712C21.7702 9.26838 20.8223 6.96908 18.9264 5.07324C17.0306 3.17741 14.7216 2.22949 11.9993 2.22949C9.29657 2.22949 6.9924 3.17741 5.08685 5.07324C3.18129 6.96908 2.22852 9.2781 2.22852 12.0003C2.22852 14.7031 3.18129 17.0073 5.08685 18.9128C6.9924 20.8184 9.30629 21.7712 12.0285 21.7712Z" fill="#4859B2"/>
+</svg>
diff --git a/www/assets/css/src/icons/logout.svg b/www/assets/css/src/icons/logout.svg
new file mode 100644
index 0000000..b70c4bb
--- /dev/null
+++ b/www/assets/css/src/icons/logout.svg
@@ -0,0 +1,3 @@
+<svg width="20" height="21" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M1.89089 20.4997C1.42422 20.4997 1.02561 20.3344 0.695052 20.0038C0.364497 19.6733 0.199219 19.2747 0.199219 18.808V1.77467C0.199219 1.30801 0.364497 0.909397 0.695052 0.578841C1.02561 0.248286 1.42422 0.0830078 1.89089 0.0830078H9.94089V1.39551H1.89089C1.79366 1.39551 1.70616 1.4344 1.62839 1.51217C1.55061 1.58995 1.51172 1.67745 1.51172 1.77467V18.808C1.51172 18.9052 1.55061 18.9927 1.62839 19.0705C1.70616 19.1483 1.79366 19.1872 1.89089 19.1872H9.94089V20.4997H1.89089ZM15.3659 14.7247L14.4034 13.7913L17.2617 10.9622H6.96588V9.62051H17.2326L14.3742 6.79134L15.3367 5.82884L19.7992 10.3205L15.3659 14.7247Z" fill="black"/>
+</svg>
diff --git a/www/assets/css/src/icons/prof-page.svg b/www/assets/css/src/icons/prof-page.svg
new file mode 100644
index 0000000..c353f4e
--- /dev/null
+++ b/www/assets/css/src/icons/prof-page.svg
@@ -0,0 +1,3 @@
+<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5.39844 21.6705C6.54566 20.6011 7.84358 19.7406 9.29219 19.0893C10.7408 18.4379 12.3109 18.1122 14.0026 18.1122C15.6943 18.1122 17.2644 18.4379 18.713 19.0893C20.1616 19.7406 21.4595 20.6011 22.6068 21.6705V5.77467C22.6068 5.67745 22.5679 5.58995 22.4901 5.51217C22.4123 5.4344 22.3248 5.39551 22.2276 5.39551H5.7776C5.68038 5.39551 5.59288 5.4344 5.5151 5.51217C5.43733 5.58995 5.39844 5.67745 5.39844 5.77467V21.6705ZM14.0318 15.633C15.0818 15.633 15.9714 15.2684 16.7005 14.5393C17.4297 13.8101 17.7943 12.9205 17.7943 11.8705C17.7943 10.8205 17.4297 9.93092 16.7005 9.20176C15.9714 8.47259 15.0818 8.10801 14.0318 8.10801C12.9818 8.10801 12.097 8.47259 11.3776 9.20176C10.6582 9.93092 10.2984 10.8205 10.2984 11.8705C10.2984 12.9205 10.6582 13.8101 11.3776 14.5393C12.097 15.2684 12.9818 15.633 14.0318 15.633ZM5.7776 23.9163C5.31094 23.9163 4.91233 23.7511 4.58177 23.4205C4.25122 23.09 4.08594 22.6913 4.08594 22.2247V5.77467C4.08594 5.30801 4.25122 4.9094 4.58177 4.57884C4.91233 4.24829 5.31094 4.08301 5.7776 4.08301H22.2276C22.6943 4.08301 23.0929 4.24829 23.4234 4.57884C23.754 4.9094 23.9193 5.30801 23.9193 5.77467V22.2247C23.9193 22.6913 23.754 23.09 23.4234 23.4205C23.0929 23.7511 22.6943 23.9163 22.2276 23.9163H5.7776ZM6.5651 22.6038H21.4401V22.3705C20.3512 21.3983 19.1797 20.6643 17.9255 20.1684C16.6714 19.6726 15.3637 19.4247 14.0026 19.4247C12.6609 19.4247 11.3582 19.6677 10.0943 20.1538C8.83038 20.64 7.65399 21.3691 6.5651 22.3413V22.6038ZM14.0609 14.2913C13.3804 14.2913 12.8019 14.058 12.3255 13.5913C11.8491 13.1247 11.6109 12.5511 11.6109 11.8705C11.6109 11.19 11.8491 10.6163 12.3255 10.1497C12.8019 9.68301 13.3707 9.44968 14.0318 9.44968C14.7123 9.44968 15.2908 9.68787 15.7672 10.1643C16.2436 10.6406 16.4818 11.2094 16.4818 11.8705C16.4818 12.5511 16.2436 13.1247 15.7672 13.5913C15.2908 14.058 14.722 14.2913 14.0609 14.2913Z" fill="black"/>
+</svg>
diff --git a/www/assets/css/src/icons/x.svg b/www/assets/css/src/icons/x.svg
new file mode 100644
index 0000000..20845d7
--- /dev/null
+++ b/www/assets/css/src/icons/x.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M1.32005 15.6122L0.386719 14.6789L7.06589 7.99971L0.386719 1.32054L1.32005 0.387207L7.99922 7.06637L14.6784 0.387207L15.6117 1.32054L8.93255 7.99971L15.6117 14.6789L14.6784 15.6122L7.99922 8.93304L1.32005 15.6122Z" fill="#4859B2"/>
+</svg>
-- 
GitLab