diff --git a/typo3/sysext/adminpanel/Classes/Controller/MainController.php b/typo3/sysext/adminpanel/Classes/Controller/MainController.php
new file mode 100644
index 0000000000000000000000000000000000000000..1ffdb97950d6e649d3bbc580025a71d8e44d77a6
--- /dev/null
+++ b/typo3/sysext/adminpanel/Classes/Controller/MainController.php
@@ -0,0 +1,176 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Adminpanel\Controller;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Adminpanel\Modules\AdminPanelModuleInterface;
+use TYPO3\CMS\Adminpanel\View\AdminPanelView;
+use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
+use TYPO3\CMS\Core\Cache\CacheManager;
+use TYPO3\CMS\Core\Http\ServerRequest;
+use TYPO3\CMS\Core\Localization\LanguageService;
+use TYPO3\CMS\Core\Service\DependencyOrderingService;
+use TYPO3\CMS\Core\SingletonInterface;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
+
+/**
+ * Main controller for the admin panel
+ *
+ * @internal
+ */
+class MainController implements SingletonInterface
+{
+    /**
+     * @var array<AdminPanelModuleInterface>
+     */
+    protected $modules = [];
+
+    /**
+     * Initializes settings for the admin panel.
+     *
+     * @param \TYPO3\CMS\Core\Http\ServerRequest $request
+     */
+    public function initialize(ServerRequest $request): void
+    {
+        $this->validateSortAndInitializeModules();
+        $this->saveConfiguration();
+
+        foreach ($this->modules as $module) {
+            if ($module->isEnabled()) {
+                $module->initializeModule($request);
+            }
+        }
+    }
+
+    /**
+     * Renders the panel - Is currently called via RenderHook in postProcessOutput
+     *
+     * @todo Still uses the legacy AdminpanelView and should be rewritten to fluid
+     *
+     * @return string
+     */
+    public function render(): string
+    {
+        // handling via legacy functions
+        $adminPanelView = GeneralUtility::makeInstance(AdminPanelView::class);
+        $adminPanelView->setModules($this->modules);
+        return $adminPanelView->display();
+    }
+
+    /**
+     * Save admin panel configuration to backend user UC
+     */
+    protected function saveConfiguration(): void
+    {
+        $input = GeneralUtility::_GP('TSFE_ADMIN_PANEL');
+        $beUser = $this->getBackendUser();
+        if (is_array($input)) {
+            // Setting
+            $beUser->uc['TSFE_adminConfig'] = array_merge(
+                !is_array($beUser->uc['TSFE_adminConfig']) ? [] : $beUser->uc['TSFE_adminConfig'],
+                $input
+            );
+            unset($beUser->uc['TSFE_adminConfig']['action']);
+
+            foreach ($this->modules as $module) {
+                if ($module->isEnabled() && $module->isOpen()) {
+                    $module->onSubmit($input);
+                }
+            }
+            // Saving
+            $beUser->writeUC();
+            // Flush fluid template cache
+            $cacheManager = new CacheManager();
+            $cacheManager->setCacheConfigurations($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']);
+            $cacheManager->getCache('fluid_template')->flush();
+        }
+    }
+
+    /**
+     * Validates, sorts and initiates the registered modules
+     *
+     * @throws \RuntimeException
+     */
+    protected function validateSortAndInitializeModules(): void
+    {
+        $modules = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules'] ?? [];
+        if (empty($modules)) {
+            return;
+        }
+        foreach ($modules as $identifier => $configuration) {
+            if (empty($configuration) || !is_array($configuration)) {
+                throw new \RuntimeException(
+                    'Missing configuration for module "' . $identifier . '".',
+                    1519490105
+                );
+            }
+            if (!is_string($configuration['module']) ||
+                empty($configuration['module']) ||
+                !class_exists($configuration['module']) ||
+                !is_subclass_of(
+                    $configuration['module'],
+                    AdminPanelModuleInterface::class
+                )
+            ) {
+                throw new \RuntimeException(
+                    'The module "' .
+                    $identifier .
+                    '" defines an invalid module class. Ensure the class exists and implements the "' .
+                    AdminPanelModuleInterface::class .
+                    '".',
+                    1519490112
+                );
+            }
+        }
+
+        $orderedModules = GeneralUtility::makeInstance(DependencyOrderingService::class)->orderByDependencies(
+            $modules
+        );
+
+        foreach ($orderedModules as $module) {
+            $this->modules[] = GeneralUtility::makeInstance($module['module']);
+        }
+    }
+
+    /**
+     * Returns LanguageService
+     *
+     * @return LanguageService
+     */
+    protected function getLanguageService(): LanguageService
+    {
+        return $GLOBALS['LANG'];
+    }
+
+    /**
+     * Returns the current BE user.
+     *
+     * @return FrontendBackendUserAuthentication
+     */
+    protected function getBackendUser(): FrontendBackendUserAuthentication
+    {
+        return $GLOBALS['BE_USER'];
+    }
+
+    /**
+     * @return TypoScriptFrontendController
+     */
+    protected function getTypoScriptFrontendController(): TypoScriptFrontendController
+    {
+        return $GLOBALS['TSFE'];
+    }
+}
diff --git a/typo3/sysext/adminpanel/Classes/Hooks/RenderHook.php b/typo3/sysext/adminpanel/Classes/Hooks/RenderHook.php
new file mode 100644
index 0000000000000000000000000000000000000000..c0a5506a20f3fd6cb0f8b2dd4467549fbe8126a9
--- /dev/null
+++ b/typo3/sysext/adminpanel/Classes/Hooks/RenderHook.php
@@ -0,0 +1,56 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Adminpanel\Hooks;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Adminpanel\Controller\MainController;
+use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
+
+/**
+ * Hook used to postProcess output - renders the admin panel
+ */
+class RenderHook
+{
+
+    /**
+     * PostProcess output hook to render the admin panel
+     * We use a hook this late in the project to make sure all data is collected and can be displayed
+     *
+     * As the main content is already rendered, we use a string replace on the content to append the adminPanel
+     * to the HTML body.
+     *
+     * @param array $params
+     * @param TypoScriptFrontendController $pObj
+     */
+    public function renderAdminPanel(array $params, TypoScriptFrontendController $pObj)
+    {
+        if ($pObj->isBackendUserLoggedIn() &&
+            $GLOBALS['BE_USER'] instanceof FrontendBackendUserAuthentication &&
+            (
+                !$GLOBALS['BE_USER']->extAdminConfig['hide'] && $pObj->config['config']['admPanel']
+            )
+        ) {
+            $mainController = GeneralUtility::makeInstance(MainController::class);
+            $pObj->content = str_ireplace(
+                '</body>',
+                $mainController->render() . '</body>',
+                $pObj->content
+            );
+        }
+    }
+}
diff --git a/typo3/sysext/adminpanel/Classes/Middleware/AdminPanelInitiator.php b/typo3/sysext/adminpanel/Classes/Middleware/AdminPanelInitiator.php
new file mode 100644
index 0000000000000000000000000000000000000000..b0dba87b80d19467da6f59b1a2fc7bbbc0576a0b
--- /dev/null
+++ b/typo3/sysext/adminpanel/Classes/Middleware/AdminPanelInitiator.php
@@ -0,0 +1,69 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Adminpanel\Middleware;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Server\MiddlewareInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+use TYPO3\CMS\Adminpanel\Controller\MainController;
+use TYPO3\CMS\Adminpanel\View\AdminPanelView;
+use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/**
+ * PSR-15 Middleware to initialize the admin panel
+ */
+class AdminPanelInitiator implements MiddlewareInterface
+{
+
+    /**
+     * Initialize the adminPanel if
+     * - backend user is logged in
+     * - at least one adminpanel functionality is enabled
+     *
+     * @param ServerRequestInterface $request
+     * @param RequestHandlerInterface $handler
+     * @return ResponseInterface
+     */
+    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
+    {
+        if ($GLOBALS['BE_USER'] instanceof FrontendBackendUserAuthentication) {
+
+            // Initialize admin panel since simulation settings are required here
+            $beUser = $GLOBALS['BE_USER'];
+            // set legacy config
+            $beUser->extAdminConfig = $beUser->getTSConfigProp('admPanel');
+            $adminPanelConfiguration = $beUser->extAdminConfig;
+            if (isset($adminPanelConfiguration['enable.'])) {
+                foreach ($adminPanelConfiguration['enable.'] as $value) {
+                    if ($value) {
+                        $adminPanelController = GeneralUtility::makeInstance(
+                            MainController::class
+                        );
+                        $adminPanelController->initialize($request);
+                        // legacy handling
+                        $beUser->adminPanel = GeneralUtility::makeInstance(AdminPanelView::class);
+                        $beUser->extAdmEnabled = true;
+                        break;
+                    }
+                }
+            }
+        }
+        return $handler->handle($request);
+    }
+}
diff --git a/typo3/sysext/adminpanel/Classes/Modules/AbstractModule.php b/typo3/sysext/adminpanel/Classes/Modules/AbstractModule.php
index 07f3c61ec22129b4f92e0a75a71ecef985cf83c6..756ed7ccd4cfc86913ac448769075efefd16b630 100644
--- a/typo3/sysext/adminpanel/Classes/Modules/AbstractModule.php
+++ b/typo3/sysext/adminpanel/Classes/Modules/AbstractModule.php
@@ -1,5 +1,5 @@
 <?php
-declare(strict_types=1);
+declare(strict_types = 1);
 
 namespace TYPO3\CMS\Adminpanel\Modules;
 
@@ -17,6 +17,7 @@ namespace TYPO3\CMS\Adminpanel\Modules;
  */
 
 use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
+use TYPO3\CMS\Core\Http\ServerRequest;
 use TYPO3\CMS\Core\Localization\LanguageService;
 
 /**
@@ -31,6 +32,16 @@ abstract class AbstractModule implements AdminPanelModuleInterface
      */
     protected $extResources = 'EXT:adminpanel/Resources/Private';
 
+    /**
+     * @var array
+     */
+    protected $mainConfiguration;
+
+    public function __construct()
+    {
+        $this->mainConfiguration = $this->getBackendUser()->getTSConfigProp('admPanel');
+    }
+
     /**
      * @inheritdoc
      */
@@ -42,7 +53,7 @@ abstract class AbstractModule implements AdminPanelModuleInterface
     /**
      * @inheritdoc
      */
-    public function initializeModule(): void
+    public function initializeModule(ServerRequest $request): void
     {
     }
 
@@ -59,8 +70,8 @@ abstract class AbstractModule implements AdminPanelModuleInterface
     {
         $identifier = $this->getIdentifier();
         $result = $this->isEnabledViaTsConfig();
-        if ($this->getBackendUser()->extAdminConfig['override.'][$identifier] ?? false) {
-            $result = (bool)$this->getBackendUser()->extAdminConfig['override.'][$identifier];
+        if ($this->mainConfiguration['override.'][$identifier] ?? false) {
+            $result = (bool)$this->mainConfiguration['override.'][$identifier];
         }
         return $result;
     }
@@ -116,7 +127,7 @@ abstract class AbstractModule implements AdminPanelModuleInterface
     {
         $labelStr = $this->getLanguageService()->getLL($key);
         if ($convertWithHtmlspecialchars) {
-            $labelStr = htmlspecialchars($labelStr);
+            $labelStr = htmlspecialchars($labelStr, ENT_QUOTES | ENT_HTML5);
         }
         return $labelStr;
     }
@@ -143,8 +154,8 @@ abstract class AbstractModule implements AdminPanelModuleInterface
         $beUser = $this->getBackendUser();
         $identifier = $this->getIdentifier();
 
-        if ($option && isset($beUser->extAdminConfig['override.'][$identifier . '.'][$option])) {
-            $returnValue = $beUser->extAdminConfig['override.'][$identifier . '.'][$option];
+        if ($option && isset($this->mainConfiguration['override.'][$identifier . '.'][$option])) {
+            $returnValue = $this->mainConfiguration['override.'][$identifier . '.'][$option];
         } else {
             $returnValue = $beUser->uc['TSFE_adminConfig'][$identifier . '_' . $option] ?? '';
         }
@@ -171,9 +182,9 @@ abstract class AbstractModule implements AdminPanelModuleInterface
     {
         $result = false;
         $identifier = $this->getIdentifier();
-        if (!empty($this->getBackendUser()->extAdminConfig['enable.']['all'])) {
+        if (!empty($this->mainConfiguration['enable.']['all'])) {
             $result = true;
-        } elseif (!empty($this->getBackendUser()->extAdminConfig['enable.'][$identifier])) {
+        } elseif (!empty($this->mainConfiguration['enable.'][$identifier])) {
             $result = true;
         }
         return $result;
diff --git a/typo3/sysext/adminpanel/Classes/Modules/AdminPanelModuleInterface.php b/typo3/sysext/adminpanel/Classes/Modules/AdminPanelModuleInterface.php
index 12a4ab949d8c4f21491a2b60e8f9b7bacebd9f52..f56445fdf9a5b7f303969f3ce6274895637b26c9 100644
--- a/typo3/sysext/adminpanel/Classes/Modules/AdminPanelModuleInterface.php
+++ b/typo3/sysext/adminpanel/Classes/Modules/AdminPanelModuleInterface.php
@@ -1,5 +1,5 @@
 <?php
-declare(strict_types=1);
+declare(strict_types = 1);
 
 namespace TYPO3\CMS\Adminpanel\Modules;
 
@@ -16,6 +16,8 @@ namespace TYPO3\CMS\Adminpanel\Modules;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Http\ServerRequest;
+
 /**
  * Interface for admin panel modules registered via EXTCONF
  *
@@ -23,6 +25,7 @@ namespace TYPO3\CMS\Adminpanel\Modules;
  */
 interface AdminPanelModuleInterface
 {
+
     /**
      * Additional JavaScript code for this module
      * (you should only use vanilla JS here, as you cannot
@@ -56,8 +59,10 @@ interface AdminPanelModuleInterface
 
     /**
      * Initialize the module - runs early in a TYPO3 request
+     *
+     * @param \TYPO3\CMS\Core\Http\ServerRequest $request
      */
-    public function initializeModule(): void;
+    public function initializeModule(ServerRequest $request): void;
 
     /**
      * Module is enabled
diff --git a/typo3/sysext/adminpanel/Classes/Modules/CacheModule.php b/typo3/sysext/adminpanel/Classes/Modules/CacheModule.php
index 5a5fc636c4c0dad4922ff07a490fb3ea4113fd38..78c86063545be9f932d67cb92afa8f671336b725 100644
--- a/typo3/sysext/adminpanel/Classes/Modules/CacheModule.php
+++ b/typo3/sysext/adminpanel/Classes/Modules/CacheModule.php
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Adminpanel\Modules;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Http\ServerRequest;
 use TYPO3\CMS\Core\Type\Bitmask\Permission;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Fluid\View\StandaloneView;
@@ -65,7 +66,7 @@ class CacheModule extends AbstractModule
     /**
      * @inheritdoc
      */
-    public function initializeModule(): void
+    public function initializeModule(ServerRequest $request): void
     {
         if ($this->getConfigurationOption('noCache')) {
             $this->getTypoScriptFrontendController()->set_no_cache('Admin Panel: No Caching', true);
diff --git a/typo3/sysext/adminpanel/Classes/Modules/EditModule.php b/typo3/sysext/adminpanel/Classes/Modules/EditModule.php
index cb52bb43b387e6cb69c44d3dbc1c1dd7b11076f5..a6cbbdf349d295ba74a1d86844148a34793c0fe4 100644
--- a/typo3/sysext/adminpanel/Classes/Modules/EditModule.php
+++ b/typo3/sysext/adminpanel/Classes/Modules/EditModule.php
@@ -1,5 +1,5 @@
 <?php
-declare(strict_types=1);
+declare(strict_types = 1);
 
 namespace TYPO3\CMS\Adminpanel\Modules;
 
@@ -16,7 +16,9 @@ namespace TYPO3\CMS\Adminpanel\Modules;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Adminpanel\Service\EditToolbarService;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Http\ServerRequest;
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Fluid\View\StandaloneView;
@@ -39,6 +41,7 @@ class EditModule extends AbstractModule
         $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templateNameAndPath));
         $view->setPartialRootPaths([$this->extResources . '/Partials']);
 
+        $editToolbarService = GeneralUtility::makeInstance(EditToolbarService::class);
         $view->assignMultiple([
             'feEdit' => ExtensionManagementUtility::isLoaded('feedit'),
             'display' => [
@@ -46,7 +49,7 @@ class EditModule extends AbstractModule
                 'fieldIcons' => $this->getConfigurationOption('displayFieldIcons'),
                 'displayIcons' => $this->getConfigurationOption('displayIcons'),
             ],
-            'toolbar' => $this->getBackendUser()->adminPanel->ext_makeToolBar(),
+            'toolbar' => $editToolbarService->createToolbar(),
             'script' => [
                 'pageUid' => (int)$this->getTypoScriptFrontendController()->page['uid'],
                 'pageModule' => $this->getPageModule(),
@@ -98,9 +101,11 @@ class EditModule extends AbstractModule
      * Initialize the edit module
      * Includes the frontend edit initialization
      *
+     * @param ServerRequest $request
+     *
      * @todo move into fe_edit (including the module)
      */
-    public function initializeModule(): void
+    public function initializeModule(ServerRequest $request): void
     {
         $extFeEditLoaded = ExtensionManagementUtility::isLoaded('feedit');
         $typoScriptFrontend = $this->getTypoScriptFrontendController();
diff --git a/typo3/sysext/adminpanel/Classes/Modules/PreviewModule.php b/typo3/sysext/adminpanel/Classes/Modules/PreviewModule.php
index b22850aef03b4b2f07228031ba4e8325b1b12030..262b5c88c6fa357da899620dac7cddf76e5d2b6e 100644
--- a/typo3/sysext/adminpanel/Classes/Modules/PreviewModule.php
+++ b/typo3/sysext/adminpanel/Classes/Modules/PreviewModule.php
@@ -1,5 +1,5 @@
 <?php
-declare(strict_types=1);
+declare(strict_types = 1);
 
 namespace TYPO3\CMS\Adminpanel\Modules;
 
@@ -17,6 +17,7 @@ namespace TYPO3\CMS\Adminpanel\Modules;
  */
 
 use TYPO3\CMS\Adminpanel\Repositories\FrontendGroupsRepository;
+use TYPO3\CMS\Core\Http\ServerRequest;
 use TYPO3\CMS\Core\Type\Bitmask\Permission;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Fluid\View\StandaloneView;
@@ -93,7 +94,10 @@ class PreviewModule extends AbstractModule
         return $this->getLanguageService()->sL($locallangFileAndPath);
     }
 
-    public function initializeModule(): void
+    /**
+     * @param ServerRequest $request
+     */
+    public function initializeModule(ServerRequest $request): void
     {
         $this->initializeFrontendPreview();
         if (GeneralUtility::_GP('ADMCMD_simUser')) {
diff --git a/typo3/sysext/adminpanel/Classes/Modules/TsDebugModule.php b/typo3/sysext/adminpanel/Classes/Modules/TsDebugModule.php
index 6b3323787e44bc893e4a554e306cbbad9710fed7..c888021053bcce3630c586d449a8ef062cfefc00 100644
--- a/typo3/sysext/adminpanel/Classes/Modules/TsDebugModule.php
+++ b/typo3/sysext/adminpanel/Classes/Modules/TsDebugModule.php
@@ -1,5 +1,6 @@
 <?php
 declare(strict_types = 1);
+
 namespace TYPO3\CMS\Adminpanel\Modules;
 
 /*
@@ -15,6 +16,7 @@ namespace TYPO3\CMS\Adminpanel\Modules;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Http\ServerRequest;
 use TYPO3\CMS\Core\TimeTracker\TimeTracker;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Fluid\View\StandaloneView;
@@ -74,7 +76,7 @@ class TsDebugModule extends AbstractModule
     /**
      * @inheritdoc
      */
-    public function initializeModule(): void
+    public function initializeModule(ServerRequest $request): void
     {
         $typoScriptFrontend = $this->getTypoScriptFrontendController();
         $typoScriptFrontend->forceTemplateParsing = (bool)$this->getConfigurationOption('forceTemplateParsing');
@@ -111,7 +113,6 @@ class TsDebugModule extends AbstractModule
     /**
      * Renders the TypoScript log as string
      *
-     * @param $output
      * @return string
      */
     private function renderTypoScriptLog(): string
diff --git a/typo3/sysext/adminpanel/Classes/Repositories/FrontendGroupsRepository.php b/typo3/sysext/adminpanel/Classes/Repositories/FrontendGroupsRepository.php
index 35881d2bce92c77b316ab601e3b46fa0eac407d7..6f184017356ac25385ed99e9e10c3ad09ca9a282 100644
--- a/typo3/sysext/adminpanel/Classes/Repositories/FrontendGroupsRepository.php
+++ b/typo3/sysext/adminpanel/Classes/Repositories/FrontendGroupsRepository.php
@@ -1,5 +1,5 @@
 <?php
-declare(strict_types=1);
+declare(strict_types = 1);
 
 namespace TYPO3\CMS\Adminpanel\Repositories;
 
@@ -110,7 +110,7 @@ class FrontendGroupsRepository
     /**
      * Returns the current BE user.
      *
-     * @return \TYPO3\CMS\Backend\FrontendBackendUserAuthentication
+     * @return FrontendBackendUserAuthentication
      */
     protected function getBackendUser(): FrontendBackendUserAuthentication
     {
diff --git a/typo3/sysext/adminpanel/Classes/Service/EditToolbarService.php b/typo3/sysext/adminpanel/Classes/Service/EditToolbarService.php
new file mode 100644
index 0000000000000000000000000000000000000000..7ccb11944841acd1bf3d1f526b1b0cb93a60e5a8
--- /dev/null
+++ b/typo3/sysext/adminpanel/Classes/Service/EditToolbarService.php
@@ -0,0 +1,273 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Adminpanel\Service;
+
+use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
+use TYPO3\CMS\Backend\Routing\UriBuilder;
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer;
+use TYPO3\CMS\Core\Imaging\Icon;
+use TYPO3\CMS\Core\Imaging\IconFactory;
+use TYPO3\CMS\Core\Localization\LanguageService;
+use TYPO3\CMS\Core\Type\Bitmask\Permission;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
+
+/**
+ * Class for the Edit Toolbar
+ *
+ * @internal
+ */
+class EditToolbarService
+{
+
+    /**
+     * Creates the tool bar links for the "edit" section of the Admin Panel.
+     *
+     * @return string A string containing images wrapped in <a>-tags linking them to proper functions.
+     */
+    public function createToolbar(): string
+    {
+        $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
+        $tsfe = $this->getTypoScriptFrontendController();
+        //  If mod.newContentElementWizard.override is set, use that extension's create new content wizard instead:
+        $tsConfig = BackendUtility::getModTSconfig($tsfe->page['uid'], 'mod');
+        $moduleName = $tsConfig['properties']['newContentElementWizard.']['override'] ?? 'new_content_element';
+        /** @var UriBuilder $uriBuilder */
+        $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
+        $perms = $this->getBackendUser()->calcPerms($tsfe->page);
+        $langAllowed = $this->getBackendUser()->checkLanguageAccess($tsfe->sys_language_uid);
+        $id = $tsfe->id;
+        $returnUrl = GeneralUtility::getIndpEnv('REQUEST_URI');
+        $classes = 'typo3-adminPanel-btn typo3-adminPanel-btn-default';
+        $output = [];
+        $output[] = '<div class="typo3-adminPanel-form-group">';
+        $output[] = '  <div class="typo3-adminPanel-btn-group" role="group">';
+
+        // History
+        /** @var UriBuilder $uriBuilder */
+        $link = (string)$uriBuilder->buildUriFromRoute(
+            'record_history',
+            [
+                'element' => 'pages:' . $id,
+                'returnUrl' => $returnUrl,
+            ]
+        );
+        $title = $this->extGetLL('edit_recordHistory');
+        $output[] = '<a class="' .
+                    $classes .
+                    '" href="' .
+                    htmlspecialchars($link, ENT_QUOTES | ENT_HTML5) .
+                    '#latest" title="' .
+                    $title .
+                    '">';
+        $output[] = '  ' . $iconFactory->getIcon('actions-document-history-open', Icon::SIZE_SMALL)->render();
+        $output[] = '</a>';
+
+        // New Content
+        if ($perms & Permission::CONTENT_EDIT && $langAllowed) {
+            $linkParameters = [
+                'id' => $id,
+                'returnUrl' => $returnUrl,
+            ];
+            if (!empty($tsfe->sys_language_uid)) {
+                $linkParameters['sys_language_uid'] = $tsfe->sys_language_uid;
+            }
+            $link = (string)$uriBuilder->buildUriFromRoute($moduleName, $linkParameters);
+            $icon = $iconFactory->getIcon('actions-add', Icon::SIZE_SMALL)->render();
+            $title = $this->extGetLL('edit_newContentElement');
+            $output[] = '<a class="' .
+                        $classes .
+                        '" href="' .
+                        htmlspecialchars($link, ENT_QUOTES | ENT_HTML5) .
+                        '" title="' .
+                        $title .
+                        '">';
+            $output[] = '  ' . $icon;
+            $output[] = '</a>';
+        }
+
+        // Move Page
+        if ($perms & Permission::PAGE_EDIT) {
+            $link = (string)$uriBuilder->buildUriFromRoute(
+                'move_element',
+                [
+                    'table' => 'pages',
+                    'uid' => $id,
+                    'returnUrl' => $returnUrl,
+                ]
+            );
+            $icon = $iconFactory->getIcon('actions-document-move', Icon::SIZE_SMALL)->render();
+            $title = $this->extGetLL('edit_move_page');
+            $output[] = '<a class="' .
+                        $classes .
+                        '" href="' .
+                        htmlspecialchars($link, ENT_QUOTES | ENT_HTML5) .
+                        '" title="' .
+                        $title .
+                        '">';
+            $output[] = '  ' . $icon;
+            $output[] = '</a>';
+        }
+
+        // New Page
+        if ($perms & Permission::PAGE_NEW) {
+            $link = (string)$uriBuilder->buildUriFromRoute(
+                'db_new',
+                [
+                    'id' => $id,
+                    'pagesOnly' => 1,
+                    'returnUrl' => $returnUrl,
+                ]
+            );
+            $icon = $iconFactory->getIcon('actions-page-new', Icon::SIZE_SMALL)->render();
+            $title = $this->extGetLL('edit_newPage');
+            $output[] = '<a class="' .
+                        $classes .
+                        '" href="' .
+                        htmlspecialchars($link, ENT_QUOTES | ENT_HTML5) .
+                        '" title="' .
+                        $title .
+                        '">';
+            $output[] = '  ' . $icon;
+            $output[] = '</a>';
+        }
+
+        // Edit Page
+        if ($perms & Permission::PAGE_EDIT) {
+            $link = (string)$uriBuilder->buildUriFromRoute(
+                'record_edit',
+                [
+                    'edit[pages][' . $id . ']' => 'edit',
+                    'noView' => 1,
+                    'returnUrl' => $returnUrl,
+                ]
+            );
+            $icon = $iconFactory->getIcon('actions-page-open', Icon::SIZE_SMALL)->render();
+            $title = $this->extGetLL('edit_editPageProperties');
+            $output[] = '<a class="' .
+                        $classes .
+                        '" href="' .
+                        htmlspecialchars($link, ENT_QUOTES | ENT_HTML5) .
+                        '" title="' .
+                        $title .
+                        '">';
+            $output[] = '  ' . $icon;
+            $output[] = '</a>';
+        }
+
+        // Edit Page Overlay
+        if ($perms & Permission::PAGE_EDIT && $tsfe->sys_language_uid && $langAllowed) {
+            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
+                ->getQueryBuilderForTable('pages');
+            $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));
+            $row = $queryBuilder
+                ->select('uid', 'pid', 't3ver_state')
+                ->from('pages')
+                ->where(
+                    $queryBuilder->expr()->eq(
+                        $GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'],
+                        $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)
+                    ),
+                    $queryBuilder->expr()->eq(
+                        $GLOBALS['TCA']['pages']['ctrl']['languageField'],
+                        $queryBuilder->createNamedParameter($tsfe->sys_language_uid, \PDO::PARAM_INT)
+                    )
+                )
+                ->setMaxResults(1)
+                ->execute()
+                ->fetch();
+            $tsfe->sys_page->versionOL('pages', $row);
+            if (is_array($row)) {
+                $link = (string)$uriBuilder->buildUriFromRoute(
+                    'record_edit',
+                    [
+                        'edit[pages][' . $row['uid'] . ']' => 'edit',
+                        'noView' => 1,
+                        'returnUrl' => $returnUrl,
+                    ]
+                );
+                $icon = $iconFactory->getIcon('mimetypes-x-content-page-language-overlay', Icon::SIZE_SMALL)
+                    ->render();
+                $title = $this->extGetLL('edit_editPageOverlay');
+                $output[] = '<a class="' .
+                            $classes .
+                            '" href="' .
+                            htmlspecialchars($link, ENT_QUOTES | ENT_HTML5) .
+                            '" title="' .
+                            $title .
+                            '">';
+                $output[] = '  ' . $icon;
+                $output[] = '</a>';
+            }
+        }
+
+        // Open list view
+        if ($this->getBackendUser()->check('modules', 'web_list')) {
+            $link = (string)$uriBuilder->buildUriFromRoute(
+                'web_list',
+                [
+                    'id' => $id,
+                    'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI'),
+                ]
+            );
+            $icon = $iconFactory->getIcon('actions-system-list-open', Icon::SIZE_SMALL)->render();
+            $title = $this->extGetLL('edit_db_list');
+            $output[] = '<a class="' .
+                        $classes .
+                        '" href="' .
+                        htmlspecialchars($link, ENT_QUOTES | ENT_HTML5) .
+                        '" title="' .
+                        $title .
+                        '">';
+            $output[] = '  ' . $icon;
+            $output[] = '</a>';
+        }
+
+        $output[] = '  </div>';
+        $output[] = '</div>';
+        return implode('', $output);
+    }
+
+    /**
+     * Translate given key
+     *
+     * @param string $key Key for a label in the $LOCAL_LANG array of "sysext/lang/Resources/Private/Language/locallang_tsfe.xlf
+     * @param bool $convertWithHtmlspecialchars If TRUE the language-label will be sent through htmlspecialchars
+     * @return string The value for the $key
+     */
+    protected function extGetLL($key, $convertWithHtmlspecialchars = true): ?string
+    {
+        $labelStr = $this->getLanguageService()->getLL($key);
+        if ($convertWithHtmlspecialchars) {
+            $labelStr = htmlspecialchars($labelStr, ENT_QUOTES | ENT_HTML5);
+        }
+        return $labelStr;
+    }
+
+    /**
+     * @return FrontendBackendUserAuthentication
+     */
+    protected function getBackendUser(): FrontendBackendUserAuthentication
+    {
+        return $GLOBALS['BE_USER'];
+    }
+
+    /**
+     * @return LanguageService
+     */
+    protected function getLanguageService(): LanguageService
+    {
+        return $GLOBALS['LANG'];
+    }
+
+    /**
+     * @return TypoScriptFrontendController
+     */
+    protected function getTypoScriptFrontendController(): TypoScriptFrontendController
+    {
+        return $GLOBALS['TSFE'];
+    }
+}
diff --git a/typo3/sysext/adminpanel/Classes/View/AdminPanelView.php b/typo3/sysext/adminpanel/Classes/View/AdminPanelView.php
index 1cc0a165aaae092ec27c60cc8ee26198cf14f245..cddd787b39ec327b21bb154deba5fd2dc5b15e84 100644
--- a/typo3/sysext/adminpanel/Classes/View/AdminPanelView.php
+++ b/typo3/sysext/adminpanel/Classes/View/AdminPanelView.php
@@ -16,19 +16,16 @@ namespace TYPO3\CMS\Adminpanel\View;
  */
 
 use TYPO3\CMS\Adminpanel\Modules\AdminPanelModuleInterface;
-use TYPO3\CMS\Backend\Utility\BackendUtility;
-use TYPO3\CMS\Core\Cache\CacheManager;
-use TYPO3\CMS\Core\Database\ConnectionPool;
-use TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer;
+use TYPO3\CMS\Adminpanel\Service\EditToolbarService;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
-use TYPO3\CMS\Core\Service\DependencyOrderingService;
-use TYPO3\CMS\Core\Type\Bitmask\Permission;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\PathUtility;
 
 /**
  * View class for the admin panel in frontend editing.
+ *
+ * @internal
  */
 class AdminPanelView
 {
@@ -63,28 +60,28 @@ class AdminPanelView
      */
     protected $modules = [];
 
+    /**
+     * @var array
+     */
+    protected $configuration;
+
     /**
      * Constructor
      */
     public function __construct()
     {
-        $this->initialize();
+        $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
     }
 
     /**
-     * Initializes settings for the admin panel.
+     * Setter for injecting new-style modules
+     *
+     * @see \TYPO3\CMS\Adminpanel\Controller\MainController::render()
+     * @param array $modules
      */
-    public function initialize()
+    public function setModules(array $modules): void
     {
-        $this->validateSortAndInitializeModules();
-        $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
-        $this->saveConfiguration();
-
-        foreach ($this->modules as $module) {
-            if ($module->isEnabled()) {
-                $module->initializeModule();
-            }
-        }
+        $this->modules = $modules;
     }
 
     /**
@@ -106,7 +103,7 @@ class AdminPanelView
     /**
      * Render a single module with header panel
      *
-     * @param \TYPO3\CMS\Frontend\AdminPanel\AdminPanelModuleInterface $module
+     * @param \TYPO3\CMS\Adminpanel\Modules\AdminPanelModuleInterface $module
      * @return string
      */
     protected function getModule(AdminPanelModuleInterface $module): string
@@ -316,80 +313,6 @@ class AdminPanelView
         return $this->getBackendUser()->uc['TSFE_adminConfig']['display_top'] ?? false;
     }
 
-    /**
-     * Save admin panel configuration to backend user UC
-     */
-    protected function saveConfiguration()
-    {
-        $input = GeneralUtility::_GP('TSFE_ADMIN_PANEL');
-        $beUser = $this->getBackendUser();
-        if (is_array($input)) {
-            // Setting
-            $beUser->uc['TSFE_adminConfig'] = array_merge(
-                !is_array($beUser->uc['TSFE_adminConfig']) ? [] : $beUser->uc['TSFE_adminConfig'],
-                $input
-            );
-            unset($beUser->uc['TSFE_adminConfig']['action']);
-
-            foreach ($this->modules as $module) {
-                if ($module->isEnabled() && $module->isOpen()) {
-                    $module->onSubmit($input);
-                }
-            }
-            // Saving
-            $beUser->writeUC();
-            // Flush fluid template cache
-            $cacheManager = new CacheManager();
-            $cacheManager->setCacheConfigurations($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']);
-            $cacheManager->getCache('fluid_template')->flush();
-        }
-    }
-
-    /**
-     * Validates, sorts and initiates the registered modules
-     *
-     * @throws \RuntimeException
-     */
-    protected function validateSortAndInitializeModules(): void
-    {
-        $modules = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules'] ?? [];
-        if (empty($modules)) {
-            return;
-        }
-        foreach ($modules as $identifier => $configuration) {
-            if (empty($configuration) || !is_array($configuration)) {
-                throw new \RuntimeException(
-                    'Missing configuration for module "' . $identifier . '".',
-                    1519490105
-                );
-            }
-            if (!is_string($configuration['module']) ||
-                empty($configuration['module']) ||
-                !class_exists($configuration['module']) ||
-                !is_subclass_of(
-                    $configuration['module'],
-                    AdminPanelModuleInterface::class
-                )) {
-                throw new \RuntimeException(
-                    'The module "' .
-                    $identifier .
-                    '" defines an invalid module class. Ensure the class exists and implements the "' .
-                    AdminPanelModuleInterface::class .
-                    '".',
-                    1519490112
-                );
-            }
-        }
-
-        $orderedModules = GeneralUtility::makeInstance(DependencyOrderingService::class)->orderByDependencies(
-            $modules
-        );
-
-        foreach ($orderedModules as $module) {
-            $this->modules[] = GeneralUtility::makeInstance($module['module']);
-        }
-    }
-
     /*****************************************************
      * Admin Panel Layout Helper functions
      ****************************************************/
@@ -397,7 +320,7 @@ class AdminPanelView
     /**
      * Wraps a string in a link which will open/close a certain part of the Admin Panel
      *
-     * @param \TYPO3\CMS\Frontend\AdminPanel\AdminPanelModuleInterface $module
+     * @param AdminPanelModuleInterface $module
      * @return string
      */
     protected function getSectionOpenerLink(AdminPanelModuleInterface $module): string
@@ -426,164 +349,14 @@ class AdminPanelView
     /**
      * Creates the tool bar links for the "edit" section of the Admin Panel.
      *
+     * @deprecated
      * @return string A string containing images wrapped in <a>-tags linking them to proper functions.
      */
     public function ext_makeToolBar()
     {
-        $tsfe = $this->getTypoScriptFrontendController();
-        //  If mod.newContentElementWizard.override is set, use that extension's create new content wizard instead:
-        $tsConfig = BackendUtility::getModTSconfig($tsfe->page['uid'], 'mod');
-        $moduleName = $tsConfig['properties']['newContentElementWizard.']['override'] ?? 'new_content_element';
-        /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
-        $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
-        $perms = $this->getBackendUser()->calcPerms($tsfe->page);
-        $langAllowed = $this->getBackendUser()->checkLanguageAccess($tsfe->sys_language_uid);
-        $id = $tsfe->id;
-        $returnUrl = GeneralUtility::getIndpEnv('REQUEST_URI');
-        $classes = 'typo3-adminPanel-btn typo3-adminPanel-btn-default';
-        $output = [];
-        $output[] = '<div class="typo3-adminPanel-form-group">';
-        $output[] = '  <div class="typo3-adminPanel-btn-group" role="group">';
-
-        // History
-        $link = (string)$uriBuilder->buildUriFromRoute(
-            'record_history',
-            [
-                'element' => 'pages:' . $id,
-                'returnUrl' => $returnUrl
-            ]
-        );
-        $title = $this->extGetLL('edit_recordHistory');
-        $output[] = '<a class="' . $classes . '" href="' . htmlspecialchars($link) . '#latest" title="' . $title . '">';
-        $output[] = '  ' . $this->iconFactory->getIcon('actions-document-history-open', Icon::SIZE_SMALL)->render();
-        $output[] = '</a>';
-
-        // New Content
-        if ($perms & Permission::CONTENT_EDIT && $langAllowed) {
-            $linkParameters = [
-                'id' => $id,
-                'returnUrl' => $returnUrl,
-            ];
-            if (!empty($tsfe->sys_language_uid)) {
-                $linkParameters['sys_language_uid'] = $tsfe->sys_language_uid;
-            }
-            $link = (string)$uriBuilder->buildUriFromRoute($moduleName, $linkParameters);
-            $icon = $this->iconFactory->getIcon('actions-add', Icon::SIZE_SMALL)->render();
-            $title = $this->extGetLL('edit_newContentElement');
-            $output[] = '<a class="' . $classes . '" href="' . htmlspecialchars($link) . '" title="' . $title . '">';
-            $output[] = '  ' . $icon;
-            $output[] = '</a>';
-        }
-
-        // Move Page
-        if ($perms & Permission::PAGE_EDIT) {
-            $link = (string)$uriBuilder->buildUriFromRoute(
-                'move_element',
-                [
-                    'table' => 'pages',
-                    'uid' => $id,
-                    'returnUrl' => $returnUrl
-                ]
-            );
-            $icon = $this->iconFactory->getIcon('actions-document-move', Icon::SIZE_SMALL)->render();
-            $title = $this->extGetLL('edit_move_page');
-            $output[] = '<a class="' . $classes . '" href="' . htmlspecialchars($link) . '" title="' . $title . '">';
-            $output[] = '  ' . $icon;
-            $output[] = '</a>';
-        }
-
-        // New Page
-        if ($perms & Permission::PAGE_NEW) {
-            $link = (string)$uriBuilder->buildUriFromRoute(
-                'db_new',
-                [
-                    'id' => $id,
-                    'pagesOnly' => 1,
-                    'returnUrl' => $returnUrl
-                ]
-            );
-            $icon = $this->iconFactory->getIcon('actions-page-new', Icon::SIZE_SMALL)->render();
-            $title = $this->extGetLL('edit_newPage');
-            $output[] = '<a class="' . $classes . '" href="' . htmlspecialchars($link) . '" title="' . $title . '">';
-            $output[] = '  ' . $icon;
-            $output[] = '</a>';
-        }
-
-        // Edit Page
-        if ($perms & Permission::PAGE_EDIT) {
-            $link = (string)$uriBuilder->buildUriFromRoute(
-                'record_edit',
-                [
-                    'edit[pages][' . $id . ']' => 'edit',
-                    'noView' => 1,
-                    'returnUrl' => $returnUrl
-                ]
-            );
-            $icon = $this->iconFactory->getIcon('actions-page-open', Icon::SIZE_SMALL)->render();
-            $title = $this->extGetLL('edit_editPageProperties');
-            $output[] = '<a class="' . $classes . '" href="' . htmlspecialchars($link) . '" title="' . $title . '">';
-            $output[] = '  ' . $icon;
-            $output[] = '</a>';
-        }
-
-        // Edit Page Overlay
-        if ($perms & Permission::PAGE_EDIT && $tsfe->sys_language_uid && $langAllowed) {
-            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
-                ->getQueryBuilderForTable('pages');
-            $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));
-            $row = $queryBuilder
-                ->select('uid', 'pid', 't3ver_state')
-                ->from('pages')
-                ->where(
-                    $queryBuilder->expr()->eq(
-                        $GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'],
-                        $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)
-                    ),
-                    $queryBuilder->expr()->eq(
-                        $GLOBALS['TCA']['pages']['ctrl']['languageField'],
-                        $queryBuilder->createNamedParameter($tsfe->sys_language_uid, \PDO::PARAM_INT)
-                    )
-                )
-                ->setMaxResults(1)
-                ->execute()
-                ->fetch();
-            $tsfe->sys_page->versionOL('pages', $row);
-            if (is_array($row)) {
-                $link = (string)$uriBuilder->buildUriFromRoute(
-                    'record_edit',
-                    [
-                        'edit[pages][' . $row['uid'] . ']' => 'edit',
-                        'noView' => 1,
-                        'returnUrl' => $returnUrl
-                    ]
-                );
-                $icon = $this->iconFactory->getIcon('mimetypes-x-content-page-language-overlay', Icon::SIZE_SMALL)->render();
-                $title = $this->extGetLL('edit_editPageOverlay');
-                $output[] = '<a class="' . $classes . '" href="' . htmlspecialchars($link) . '" title="' . $title . '">';
-                $output[] = '  ' . $icon;
-                $output[] = '</a>';
-            }
-        }
-
-        // Open list view
-        if ($this->getBackendUser()->check('modules', 'web_list')) {
-            $link = (string)$uriBuilder->buildUriFromRoute(
-                'web_list',
-                [
-                    'id' => $id,
-                    'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
-                ]
-            );
-            $icon = $this->iconFactory->getIcon('actions-system-list-open', Icon::SIZE_SMALL)->render();
-            $title = $this->extGetLL('edit_db_list');
-            $output[] = '<a class="' . $classes . '" href="' . htmlspecialchars($link) . '" title="' . $title . '">';
-            $output[] = '  ' . $icon;
-            $output[] = '</a>';
-        }
-
-        $output[] = '  </div>';
-        $output[] = '</div>';
-        return implode('', $output);
+        trigger_error('', E_USER_DEPRECATED);
+        $editToolbarService = GeneralUtility::makeInstance(EditToolbarService::class);
+        return $editToolbarService->createToolbar();
     }
 
     /**
@@ -662,9 +435,9 @@ class AdminPanelView
         // Returns TRUE if the module checked is "preview" and the forcePreview flag is set.
         if ($key === 'preview' && $this->ext_forcePreview) {
             $result = true;
-        } elseif (!empty($this->getBackendUser()->extAdminConfig['enable.']['all'])) {
+        } elseif (!empty($this->configuration['enable.']['all'])) {
             $result = true;
-        } elseif (!empty($this->getBackendUser()->extAdminConfig['enable.'][$key])) {
+        } elseif (!empty($this->configuration['enable.'][$key])) {
             $result = true;
         }
         return $result;
@@ -707,20 +480,20 @@ class AdminPanelView
         // deprecated
         if (
             $sectionName === 'edit' && (
-                $val === 'displayIcons' && $beUser->extAdminConfig['module.']['edit.']['forceDisplayIcons'] ||
-                $val === 'displayFieldIcons' && $beUser->extAdminConfig['module.']['edit.']['forceDisplayFieldIcons'] ||
-                $val === 'editNoPopup' && $beUser->extAdminConfig['module.']['edit.']['forceNoPopup']
+                $val === 'displayIcons' && $this->configuration['module.']['edit.']['forceDisplayIcons'] ||
+                $val === 'displayFieldIcons' && $this->configuration['module.']['edit.']['forceDisplayFieldIcons'] ||
+                $val === 'editNoPopup' && $this->configuration['module.']['edit.']['forceNoPopup']
             )
         ) {
             return true;
         }
 
         // Override all settings with user TSconfig
-        if ($val && isset($beUser->extAdminConfig['override.'][$sectionName . '.'][$val])) {
-            return $beUser->extAdminConfig['override.'][$sectionName . '.'][$val];
+        if ($val && isset($this->configuration['override.'][$sectionName . '.'][$val])) {
+            return $this->configuration['override.'][$sectionName . '.'][$val];
         }
-        if (!$val && isset($beUser->extAdminConfig['override.'][$sectionName])) {
-            return $beUser->extAdminConfig['override.'][$sectionName];
+        if (!$val && isset($this->configuration['override.'][$sectionName])) {
+            return $this->configuration['override.'][$sectionName];
         }
 
         $returnValue = $val ? $beUser->uc['TSFE_adminConfig'][$sectionName . '_' . $val] : 1;
diff --git a/typo3/sysext/adminpanel/Configuration/RequestMiddlewares.php b/typo3/sysext/adminpanel/Configuration/RequestMiddlewares.php
new file mode 100644
index 0000000000000000000000000000000000000000..ffa8eb191e7ed9df10f979980bafd91dafcd3c72
--- /dev/null
+++ b/typo3/sysext/adminpanel/Configuration/RequestMiddlewares.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ * An array consisting of implementations of middlewares for a middleware stack to be registered
+ *  'stackname' => [
+ *      'middleware-identifier' => [
+ *         'target' => classname or callable
+ *         'before/after' => array of dependencies
+ *      ]
+ *   ]
+ */
+return [
+    'frontend' => [
+        'typo3/cms-adminpanel/initiator' => [
+            'target' => \TYPO3\CMS\Adminpanel\Middleware\AdminPanelInitiator::class,
+            'after' => [
+                'typo3/cms-frontend/tsfe',
+                'typo3/cms-frontend/authentication',
+                'typo3/cms-frontend/backend-user-authentication',
+            ]
+        ],
+    ]
+];
diff --git a/typo3/sysext/adminpanel/Tests/Unit/View/AdminPanelViewTest.php b/typo3/sysext/adminpanel/Tests/Unit/View/AdminPanelViewTest.php
deleted file mode 100644
index bfd416b6fc2a71e11aa302af9596a54b2bed3724..0000000000000000000000000000000000000000
--- a/typo3/sysext/adminpanel/Tests/Unit/View/AdminPanelViewTest.php
+++ /dev/null
@@ -1,78 +0,0 @@
-<?php
-declare(strict_types=1);
-
-namespace TYPO3\CMS\Adminpanel\Tests\Unit\View;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Adminpanel\Tests\Unit\View\Fixtures\AdminPanelDisabledModuleFixture;
-use TYPO3\CMS\Adminpanel\Tests\Unit\View\Fixtures\AdminPanelEnabledShownOnSubmitInitializeModuleFixture;
-use TYPO3\CMS\Adminpanel\View\AdminPanelView;
-use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
-use TYPO3\CMS\Core\Imaging\IconFactory;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
-
-/**
- * Test case
- */
-class AdminPanelViewTest extends UnitTestCase
-{
-    public function setUp()
-    {
-        parent::setUp();
-        $iconFactoryProphecy = $this->prophesize(IconFactory::class);
-        GeneralUtility::addInstance(IconFactory::class, $iconFactoryProphecy->reveal());
-        $beUserProphecy = $this->prophesize(BackendUserAuthentication::class);
-        $GLOBALS['BE_USER'] = $beUserProphecy->reveal();
-    }
-
-    /**
-     * @test
-     */
-    public function initializeCallsOnSubmitIfInputVarsAreSet()
-    {
-        $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules'] = [
-            'fixtureOnSubmit' => [
-                'module' => AdminPanelEnabledShownOnSubmitInitializeModuleFixture::class,
-            ],
-        ];
-
-        $postVars = ['preview_showFluidDebug' => '1'];
-        $_GET['TSFE_ADMIN_PANEL'] = $postVars;
-
-        $this->expectExceptionCode('1519997815');
-
-        new AdminPanelView();
-    }
-
-    /**
-     * @test
-     */
-    public function initializeCallsInitializeModulesForEnabledModules()
-    {
-        $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules'] = [
-            'enabledModule' => [
-                'module' => AdminPanelEnabledShownOnSubmitInitializeModuleFixture::class,
-            ],
-            'disabledModule' => [
-                'module' => AdminPanelDisabledModuleFixture::class,
-                'before' => ['enabledModule'],
-            ],
-        ];
-
-        $this->expectExceptionCode(1519999273);
-        new AdminPanelView();
-    }
-}
diff --git a/typo3/sysext/adminpanel/Tests/Unit/View/Fixtures/AdminPanelDisabledModuleFixture.php b/typo3/sysext/adminpanel/Tests/Unit/View/Fixtures/AdminPanelDisabledModuleFixture.php
deleted file mode 100644
index d9cc6741904ab90a0ed47703b41f982e16c9c926..0000000000000000000000000000000000000000
--- a/typo3/sysext/adminpanel/Tests/Unit/View/Fixtures/AdminPanelDisabledModuleFixture.php
+++ /dev/null
@@ -1,141 +0,0 @@
-<?php
-declare(strict_types=1);
-namespace TYPO3\CMS\Adminpanel\Tests\Unit\View\Fixtures;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-use TYPO3\CMS\Adminpanel\Modules\AdminPanelModuleInterface;
-
-class AdminPanelDisabledModuleFixture implements AdminPanelModuleInterface
-{
-
-    /**
-     * Additional JavaScript code for this module
-     * (you should only use vanilla JS here, as you cannot
-     * rely on the web site providing a specific framework)
-     *
-     * @return string
-     */
-    public function getAdditionalJavaScriptCode(): string
-    {
-        return '';
-    }
-
-    /**
-     * Module content as rendered HTML
-     *
-     * @return string
-     */
-    public function getContent(): string
-    {
-        return '';
-    }
-
-    /**
-     * Identifier for this module,
-     * for example "preview" or "cache"
-     *
-     * @return string
-     */
-    public function getIdentifier(): string
-    {
-        return '';
-    }
-
-    /**
-     * Module label
-     *
-     * @return string
-     */
-    public function getLabel(): string
-    {
-        return '';
-    }
-
-    /**
-     * Initialize the module - runs early in a TYPO3 request
-     */
-    public function initializeModule(): void
-    {
-        throw new \RuntimeException('I should not be initialized.', 1519999375);
-    }
-
-    /**
-     * Module is enabled
-     * -> should be initialized
-     * A module may be enabled but not shown
-     * -> only the initializeModule() method
-     * will be called
-     *
-     * @return bool
-     */
-    public function isEnabled(): bool
-    {
-        return false;
-    }
-
-    /**
-     * Module is open
-     * -> module is enabled
-     * -> module panel is shown and open
-     *
-     * @return bool
-     */
-    public function isOpen(): bool
-    {
-        return true;
-    }
-
-    /**
-     * Module is shown
-     * -> module is enabled
-     * -> module panel should be displayed
-     *
-     * @return bool
-     */
-    public function isShown(): bool
-    {
-        return true;
-    }
-
-    /**
-     * Executed on saving / submit of the configuration form
-     * Can be used to react to changed settings
-     * (for example: clearing a specific cache)
-     *
-     * @param array $input
-     */
-    public function onSubmit(array $input): void
-    {
-    }
-
-    /**
-     * Does this module need a form submit?
-     *
-     * @return bool
-     */
-    public function showFormSubmitButton(): bool
-    {
-        return true;
-    }
-
-    /**
-     * Returns a string array with javascript files that will be rendered after the module
-     *
-     * @return array
-     */
-    public function getJavaScriptFiles(): array
-    {
-        return [];
-    }
-}
diff --git a/typo3/sysext/adminpanel/Tests/Unit/View/Fixtures/AdminPanelEnabledShownOnSubmitInitializeModuleFixture.php b/typo3/sysext/adminpanel/Tests/Unit/View/Fixtures/AdminPanelEnabledShownOnSubmitInitializeModuleFixture.php
deleted file mode 100644
index 0835228afb74b9cccc0bf35998ba0733ba821508..0000000000000000000000000000000000000000
--- a/typo3/sysext/adminpanel/Tests/Unit/View/Fixtures/AdminPanelEnabledShownOnSubmitInitializeModuleFixture.php
+++ /dev/null
@@ -1,142 +0,0 @@
-<?php
-declare(strict_types=1);
-namespace TYPO3\CMS\Adminpanel\Tests\Unit\View\Fixtures;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-use TYPO3\CMS\Adminpanel\Modules\AdminPanelModuleInterface;
-
-class AdminPanelEnabledShownOnSubmitInitializeModuleFixture implements AdminPanelModuleInterface
-{
-
-    /**
-     * Additional JavaScript code for this module
-     * (you should only use vanilla JS here, as you cannot
-     * rely on the web site providing a specific framework)
-     *
-     * @return string
-     */
-    public function getAdditionalJavaScriptCode(): string
-    {
-        return '';
-    }
-
-    /**
-     * Module content as rendered HTML
-     *
-     * @return string
-     */
-    public function getContent(): string
-    {
-        return '';
-    }
-
-    /**
-     * Identifier for this module,
-     * for example "preview" or "cache"
-     *
-     * @return string
-     */
-    public function getIdentifier(): string
-    {
-        return '';
-    }
-
-    /**
-     * Module label
-     *
-     * @return string
-     */
-    public function getLabel(): string
-    {
-        return '';
-    }
-
-    /**
-     * Initialize the module - runs early in a TYPO3 request
-     */
-    public function initializeModule(): void
-    {
-        throw new \RuntimeException('initialized.', 1519999273);
-    }
-
-    /**
-     * Module is enabled
-     * -> should be initialized
-     * A module may be enabled but not shown
-     * -> only the initializeModule() method
-     * will be called
-     *
-     * @return bool
-     */
-    public function isEnabled(): bool
-    {
-        return true;
-    }
-
-    /**
-     * Module is open
-     * -> module is enabled
-     * -> module panel is shown and open
-     *
-     * @return bool
-     */
-    public function isOpen(): bool
-    {
-        return true;
-    }
-
-    /**
-     * Module is shown
-     * -> module is enabled
-     * -> module panel should be displayed
-     *
-     * @return bool
-     */
-    public function isShown(): bool
-    {
-        return true;
-    }
-
-    /**
-     * Executed on saving / submit of the configuration form
-     * Can be used to react to changed settings
-     * (for example: clearing a specific cache)
-     *
-     * @param array $input
-     */
-    public function onSubmit(array $input): void
-    {
-        throw new \RuntimeException('Catch me if you can!', 1519997815);
-    }
-
-    /**
-     * Does this module need a form submit?
-     *
-     * @return bool
-     */
-    public function showFormSubmitButton(): bool
-    {
-        return true;
-    }
-
-    /**
-     * Returns a string array with javascript files that will be rendered after the module
-     *
-     * @return array
-     */
-    public function getJavaScriptFiles(): array
-    {
-        return [];
-    }
-}
diff --git a/typo3/sysext/adminpanel/composer.json b/typo3/sysext/adminpanel/composer.json
index 15c401cee7ae7e357b074aef53287685e37057c7..5fe988055c64247458b586ad4551fcd057bff56b 100644
--- a/typo3/sysext/adminpanel/composer.json
+++ b/typo3/sysext/adminpanel/composer.json
@@ -13,8 +13,13 @@
 		"sort-packages": true
 	},
 	"require": {
+		"typo3/cms-backend": "9.2.*@dev",
 		"typo3/cms-core": "9.2.*@dev",
-		"typo3/cms-frontend": "9.2.*@dev"
+		"typo3/cms-fluid": "9.2.*@dev",
+		"typo3/cms-frontend": "9.2.*@dev",
+		"psr/http-message": "~1.0",
+		"psr/http-server-handler": "^1.0",
+		"psr/http-server-middleware": "^1.0"
 	},
 	"conflict": {
 		"typo3/cms": "*"
diff --git a/typo3/sysext/adminpanel/ext_localconf.php b/typo3/sysext/adminpanel/ext_localconf.php
index 0094d2f69a0037b8fa99d2b2a7d2ac271f3c1b00..ba181f018207b32bd2c92ea114a199d21c4bab97 100644
--- a/typo3/sysext/adminpanel/ext_localconf.php
+++ b/typo3/sysext/adminpanel/ext_localconf.php
@@ -1,4 +1,7 @@
 <?php
+defined('TYPO3_MODE') or die();
+
+$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-output'][] = \TYPO3\CMS\Adminpanel\Hooks\RenderHook::class . '->renderAdminPanel';
 
 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules'] = [
     'preview' => [
diff --git a/typo3/sysext/backend/Classes/FrontendBackendUserAuthentication.php b/typo3/sysext/backend/Classes/FrontendBackendUserAuthentication.php
index cd087423327c4dc1da88750994b9b2a793d1e48a..6c24767ccf2be484ad94e8d104812791914f66e3 100644
--- a/typo3/sysext/backend/Classes/FrontendBackendUserAuthentication.php
+++ b/typo3/sysext/backend/Classes/FrontendBackendUserAuthentication.php
@@ -15,6 +15,7 @@ namespace TYPO3\CMS\Backend;
  */
 
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
+use TYPO3\CMS\Core\Compatibility\PublicPropertyDeprecationTrait;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
 use TYPO3\CMS\Core\Database\Query\QueryHelper;
@@ -29,6 +30,19 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
  */
 class FrontendBackendUserAuthentication extends BackendUserAuthentication
 {
+    use PublicPropertyDeprecationTrait;
+
+    /**
+     * Properties which have been moved to protected status from public
+     *
+     * @var array
+     */
+    protected $deprecatedPublicProperties = [
+        'extAdmEnabled' => 'Using $extAdmEnabled of class FrontendBackendUserAuthentication from the outside is discouraged, as this variable is only used for internal storage.',
+        'adminPanel' => 'Using $adminPanel of class FrontendBackendUserAuthentication from the outside is discouraged, as this variable is only used for internal storage.',
+        'extAdminConfig' => 'Using $extAdminConfig of class FrontendBackendUserAuthentication from the outside is discouraged, as this variable is only used for internal storage.',
+    ];
+
     /**
      * Form field with login name.
      *
@@ -69,11 +83,13 @@ class FrontendBackendUserAuthentication extends BackendUserAuthentication
      * General flag which is set if the adminpanel is enabled at all.
      *
      * @var bool
+     * @deprecated since TYPO3v9, property will be removed in TYPO3 v10 - see extension "adminpanel" for new API
      */
     public $extAdmEnabled = false;
 
     /**
      * @var \TYPO3\CMS\Adminpanel\View\AdminPanelView Instance of admin panel
+     * @deprecated since TYPO3v9, property will be removed in TYPO3 v10 - see extension "adminpanel" for new API
      */
     public $adminPanel = null;
 
@@ -84,58 +100,39 @@ class FrontendBackendUserAuthentication extends BackendUserAuthentication
 
     /**
      * @var array
+     * @deprecated since TYPO3v9, property will be removed in TYPO3 v10 - see extension "adminpanel" for new API
      */
     public $extAdminConfig = [];
 
     /**
      * Initializes the admin panel.
+     *
+     * @deprecated since TYPO3v9 - rewritten as middleware
      */
     public function initializeAdminPanel()
     {
-        $this->extAdminConfig = $this->getTSConfigProp('admPanel');
-        if (isset($this->extAdminConfig['enable.'])) {
-            foreach ($this->extAdminConfig['enable.'] as $value) {
-                if ($value) {
-                    $this->adminPanel = GeneralUtility::makeInstance(\TYPO3\CMS\Adminpanel\View\AdminPanelView::class);
-                    $this->extAdmEnabled = true;
-                    break;
-                }
-            }
-        }
+        trigger_error('Method will be removed in TYPO3 v10 - initialization is done via middleware.', E_USER_DEPRECATED);
     }
 
     /**
      * Initializes frontend editing.
+     *
+     * @deprecated since TYPO3v9 - rewritten as middleware
      */
     public function initializeFrontendEdit()
     {
-        if (isset($this->extAdminConfig['enable.']) && $this->isFrontendEditingActive()) {
-            foreach ($this->extAdminConfig['enable.'] as $value) {
-                if ($value) {
-                    if ($GLOBALS['TSFE'] instanceof \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController) {
-                        // Grab the Page TSConfig property that determines which controller to use.
-                        $pageTSConfig = $GLOBALS['TSFE']->getPagesTSconfig();
-                        $controllerKey = $pageTSConfig['TSFE.']['frontendEditingController'] ?? 'default';
-                    } else {
-                        $controllerKey = 'default';
-                    }
-                    $controllerClass = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController'][$controllerKey];
-                    if ($controllerClass) {
-                        $this->frontendEdit = GeneralUtility::makeInstance($controllerClass);
-                    }
-                    break;
-                }
-            }
-        }
+        trigger_error('Method will be removed in TYPO3 v10 - initialization is done via middleware.', E_USER_DEPRECATED);
     }
 
     /**
      * Determines whether frontend editing is currently active.
      *
+     * @deprecated since TYPO3 v9 - see ext "feedit" for API
      * @return bool Whether frontend editing is active
      */
     public function isFrontendEditingActive()
     {
+        trigger_error('Method will be removed in TYPO3 v10 - use underlying TSFE directly.', E_USER_DEPRECATED);
         return $this->extAdmEnabled && (
             $this->adminPanel->isAdminModuleEnabled('edit') ||
             (int)$GLOBALS['TSFE']->displayEditIcons === 1 ||
@@ -146,20 +143,24 @@ class FrontendBackendUserAuthentication extends BackendUserAuthentication
     /**
      * Delegates to the appropriate view and renders the admin panel content.
      *
+     * @deprecated since TYPO3v9 - see ext "adminpanel" for new API
      * @return string.
      */
     public function displayAdminPanel()
     {
+        trigger_error('Method will be removed in TYPO3 v10 - use MainController of adminpanel extension.', E_USER_DEPRECATED);
         return $this->adminPanel->display();
     }
 
     /**
      * Determines whether the admin panel is enabled and visible.
      *
+     * @deprecated since TYPO3v9 - see ext "adminpanel" for new API
      * @return bool true if the admin panel is enabled and visible
      */
     public function isAdminPanelVisible()
     {
+        trigger_error('Method will be removed in TYPO3 v10 - use new adminpanel API instead.', E_USER_DEPRECATED);
         return $this->extAdmEnabled && !$this->extAdminConfig['hide'] && $GLOBALS['TSFE']->config['config']['admPanel'];
     }
 
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-84641-DeprecatedAdminPanelRelatedMethods.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-84641-DeprecatedAdminPanelRelatedMethods.rst
new file mode 100644
index 0000000000000000000000000000000000000000..051f5ed17f8e0780389fafdfb37b0d5267741af4
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-84641-DeprecatedAdminPanelRelatedMethods.rst
@@ -0,0 +1,53 @@
+.. include:: ../../Includes.txt
+
+===============================================================================================================
+Deprecation: #84641 - Deprecated AdminPanel related methods and properties in FrontendBackendUserAuthentication
+===============================================================================================================
+
+See :issue:`84641`
+
+Description
+===========
+
+The admin panel has been extracted into an own extension. To enable users to de-activate the admin panel completely, the hard coupling between the extension and other parts of the core had to be resolved. The admin panel now takes care of its own initialization and provides API methods related to its functionality.
+The following API methods and properties located in `FrontendBackendUserAuthentication` have been deprecated:
+
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::$adminPanel`
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::$extAdminConfig`
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::$extAdmEnabled`
+
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::initializeAdminPanel()`
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::initializeFrontendEdit()`
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::isFrontendEditingActive()`
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::displayAdminPanel()`
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::isAdminPanelVisible()`
+
+
+Impact
+======
+
+Using any of the methods will trigger a deprecation warning.
+
+
+Affected Installations
+======================
+
+Any installation directly calling one of the mentioned methods or properties.
+
+
+Migration
+=========
+
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::$adminPanel` - use `MainController` of adminpanel instead
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::$extAdminConfig` - load directly from TSConfig if needed
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::$extAdmEnabled` - check directly against TSConfig if necessary
+
+Both initialization methods `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::initializeAdminPanel` and
+`\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::initializeFrontendEdit` were rewritten as PSR-15 middlewares,
+remove any calls as they are not necessary anymore.
+
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::isFrontendEditingActive` and `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::isAdminPanelVisible` - check against TSFE directly
+
+* `\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::displayAdminPanel` - use `MainController::render()` instead
+
+.. index:: Frontend, PHP-API, PartiallyScanned
diff --git a/typo3/sysext/feedit/Classes/FrontendEditPanel.php b/typo3/sysext/feedit/Classes/FrontendEditPanel.php
index 54addc2f3ace7e63ca86fa98afa50c69635bea10..01331773c82913f244d754e4fd6f253a41b20211 100644
--- a/typo3/sysext/feedit/Classes/FrontendEditPanel.php
+++ b/typo3/sysext/feedit/Classes/FrontendEditPanel.php
@@ -13,7 +13,7 @@ namespace TYPO3\CMS\Feedit;
  *
  * The TYPO3 project - inspiring people to share!
  */
-use TYPO3\CMS\Adminpanel\View\AdminPanelView;
+use TYPO3\CMS\Adminpanel\Service\EditToolbarService;
 use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
@@ -97,8 +97,9 @@ class FrontendEditPanel
         $hideField = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled'];
 
         $panel = '';
-        if (isset($allow['toolbar']) && $this->backendUser->adminPanel instanceof AdminPanelView) {
-            $panel .= $this->backendUser->adminPanel->ext_makeToolBar();
+        if (isset($allow['toolbar'])) {
+            $editToolbarService = GeneralUtility::makeInstance(EditToolbarService::class);
+            $panel .= $editToolbarService->createToolbar();
         }
         if (isset($allow['edit'])) {
             $icon = '<span title="' . $this->backendUser->extGetLL('p_editRecord') . '">' . $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render('inline') . '</span>';
diff --git a/typo3/sysext/feedit/Classes/Middleware/FrontendEditInitiator.php b/typo3/sysext/feedit/Classes/Middleware/FrontendEditInitiator.php
new file mode 100644
index 0000000000000000000000000000000000000000..96c7ede4ec2d747b18fb583f6bf7cf4685e4b21a
--- /dev/null
+++ b/typo3/sysext/feedit/Classes/Middleware/FrontendEditInitiator.php
@@ -0,0 +1,67 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Feedit\Middleware;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Server\MiddlewareInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
+
+/**
+ * PSR-15 middleware initializing frontend editing
+ */
+class FrontendEditInitiator implements MiddlewareInterface
+{
+
+    /**
+     * Process an incoming server request and return a response, optionally delegating
+     * response creation to a handler.
+     *
+     * @param ServerRequestInterface $request
+     * @param RequestHandlerInterface $handler
+     * @return ResponseInterface
+     */
+    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
+    {
+        if ($GLOBALS['BE_USER'] instanceof FrontendBackendUserAuthentication) {
+            $config = $GLOBALS['BE_USER']->getTSConfigProp('admPanel');
+            $active = (int)$GLOBALS['TSFE']->displayEditIcons === 1 || (int)$GLOBALS['TSFE']->displayFieldEditIcons === 1;
+            if ($active && isset($config['enable.'])) {
+                foreach ($config['enable.'] as $value) {
+                    if ($value) {
+                        if ($GLOBALS['TSFE'] instanceof TypoScriptFrontendController) {
+                            // Grab the Page TSConfig property that determines which controller to use.
+                            $pageTSConfig = $GLOBALS['TSFE']->getPagesTSconfig();
+                            $controllerKey = $pageTSConfig['TSFE.']['frontendEditingController'] ?? 'default';
+                        } else {
+                            $controllerKey = 'default';
+                        }
+                        $controllerClass = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController'][$controllerKey];
+                        if ($controllerClass) {
+                            $GLOBALS['BE_USER']->frontendEdit = GeneralUtility::makeInstance($controllerClass);
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+        return $handler->handle($request);
+    }
+}
diff --git a/typo3/sysext/feedit/Configuration/RequestMiddlewares.php b/typo3/sysext/feedit/Configuration/RequestMiddlewares.php
new file mode 100644
index 0000000000000000000000000000000000000000..71ca4acff44203a298ee908bc5495d3f4dbbf65a
--- /dev/null
+++ b/typo3/sysext/feedit/Configuration/RequestMiddlewares.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * An array consisting of implementations of middlewares for a middleware stack to be registered
+ *  'stackname' => [
+ *      'middleware-identifier' => [
+ *         'target' => classname or callable
+ *         'before/after' => array of dependencies
+ *      ]
+ *   ]
+ */
+return [
+    'frontend' => [
+        'typo3/cms-frontendedit/initiator' => [
+            'target' => \TYPO3\CMS\Feedit\Middleware\FrontendEditInitiator::class,
+            'after' => [
+                'typo3/cms-adminpanel/initiator',
+                'typo3/cms-frontend/page-resolver',
+            ]
+        ],
+    ]
+];
diff --git a/typo3/sysext/feedit/composer.json b/typo3/sysext/feedit/composer.json
index 45608ec6d41b3848977ec5fa03f8fc3400ff6ea9..05792433669a594ada1edcefd6ec329f16bc6df5 100644
--- a/typo3/sysext/feedit/composer.json
+++ b/typo3/sysext/feedit/composer.json
@@ -13,7 +13,13 @@
 		"sort-packages": true
 	},
 	"require": {
-		"typo3/cms-core": "9.2.*@dev"
+		"typo3/cms-adminpanel": "9.2.*@dev",
+		"typo3/cms-backend": "9.2.*@dev",
+		"typo3/cms-core": "9.2.*@dev",
+		"typo3/cms-frontend": "9.2.*@dev",
+		"psr/http-message": "~1.0",
+		"psr/http-server-handler": "^1.0",
+		"psr/http-server-middleware": "^1.0"
 	},
 	"conflict": {
 		"typo3/cms": "*"
diff --git a/typo3/sysext/frontend/Classes/Http/RequestHandler.php b/typo3/sysext/frontend/Classes/Http/RequestHandler.php
index c7755dab753adcbefc73ede03f487e4d5758e672..e00620edc6d78456957020f2e91a6807718eccbf 100644
--- a/typo3/sysext/frontend/Classes/Http/RequestHandler.php
+++ b/typo3/sysext/frontend/Classes/Http/RequestHandler.php
@@ -1,5 +1,6 @@
 <?php
 declare(strict_types = 1);
+
 namespace TYPO3\CMS\Frontend\Http;
 
 /*
@@ -18,7 +19,6 @@ namespace TYPO3\CMS\Frontend\Http;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use Psr\Http\Server\RequestHandlerInterface as PsrRequestHandlerInterface;
-use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
 use TYPO3\CMS\Core\FrontendEditing\FrontendEditingController;
 use TYPO3\CMS\Core\Http\NullResponse;
 use TYPO3\CMS\Core\Http\RequestHandlerInterface;
@@ -161,11 +161,6 @@ class RequestHandler implements RequestHandlerInterface, PsrRequestHandlerInterf
         // Finish timetracking
         $this->timeTracker->pull();
 
-        // Admin panel
-        if ($controller->isBackendUserLoggedIn() && $GLOBALS['BE_USER'] instanceof FrontendBackendUserAuthentication && $GLOBALS['BE_USER']->isAdminPanelVisible()) {
-            $controller->content = str_ireplace('</body>', $GLOBALS['BE_USER']->displayAdminPanel() . '</body>', $controller->content);
-        }
-
         if ($isOutputting) {
             $response->getBody()->write($controller->content);
         }
diff --git a/typo3/sysext/frontend/Classes/Middleware/BackendUserAuthenticator.php b/typo3/sysext/frontend/Classes/Middleware/BackendUserAuthenticator.php
index 9f64161c1871b480c4b6d458e8820deed3349bda..161108564a1eda3b5f202f748ba6af0039f992ae 100644
--- a/typo3/sysext/frontend/Classes/Middleware/BackendUserAuthenticator.php
+++ b/typo3/sysext/frontend/Classes/Middleware/BackendUserAuthenticator.php
@@ -1,5 +1,6 @@
 <?php
 declare(strict_types = 1);
+
 namespace TYPO3\CMS\Frontend\Middleware;
 
 /*
@@ -83,8 +84,6 @@ class BackendUserAuthenticator implements MiddlewareInterface
             Bootstrap::initializeLanguageObject();
             Bootstrap::initializeBackendRouter();
             Bootstrap::loadExtTables();
-            // Initialize admin panel since simulation settings are required here
-            $GLOBALS['BE_USER']->initializeAdminPanel();
         }
 
         return $handler->handle($request);
diff --git a/typo3/sysext/frontend/composer.json b/typo3/sysext/frontend/composer.json
index 133c0b6f13b48fd7226f3c726423d8b8f2e3fe3f..107b11d351bbd6e6adfea2ded45489e08328ba3f 100644
--- a/typo3/sysext/frontend/composer.json
+++ b/typo3/sysext/frontend/composer.json
@@ -18,6 +18,9 @@
 	"conflict": {
 		"typo3/cms": "*"
 	},
+	"suggest": {
+		"typo3/cms-adminpanel": "Provides additional information and functionality for backend users in the frontend."
+	},
 	"replace": {
 		"frontend": "*"
 	},
diff --git a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php
index d7b3831c7f73b0d424ca8ddf39501edc6fd9a1ca..4808ea5259994caf2308aaf4827e1d40f1ac4e36 100644
--- a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php
+++ b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php
@@ -2081,4 +2081,39 @@ return [
             'Deprecation-84637-TemplateService-linkDataFunctionalityMovedInPageLinkBuilder.rst',
         ],
     ],
+    'TYPO3\CMS\Backend\FrontendBackendUserAuthentication->initializeAdminPanel' => [
+        'numberOfMandatoryArguments' => 0,
+        'maximumNumberOfArguments' => 0,
+        'restFiles' => [
+            'Deprecation-84641-DeprecatedAdminPanelRelatedMethods.rst',
+        ],
+    ],
+    'TYPO3\CMS\Backend\FrontendBackendUserAuthentication->initializeFrontendEdit' => [
+        'numberOfMandatoryArguments' => 0,
+        'maximumNumberOfArguments' => 0,
+        'restFiles' => [
+            'Deprecation-84641-DeprecatedAdminPanelRelatedMethods.rst',
+        ],
+    ],
+    'TYPO3\CMS\Backend\FrontendBackendUserAuthentication->isFrontendEditingActive' => [
+        'numberOfMandatoryArguments' => 0,
+        'maximumNumberOfArguments' => 0,
+        'restFiles' => [
+            'Deprecation-84641-DeprecatedAdminPanelRelatedMethods.rst',
+        ],
+    ],
+    'TYPO3\CMS\Backend\FrontendBackendUserAuthentication->displayAdminPanel' => [
+        'numberOfMandatoryArguments' => 0,
+        'maximumNumberOfArguments' => 0,
+        'restFiles' => [
+            'Deprecation-84641-DeprecatedAdminPanelRelatedMethods.rst',
+        ],
+    ],
+    'TYPO3\CMS\Backend\FrontendBackendUserAuthentication->isAdminPanelVisible' => [
+        'numberOfMandatoryArguments' => 0,
+        'maximumNumberOfArguments' => 0,
+        'restFiles' => [
+            'Deprecation-84641-DeprecatedAdminPanelRelatedMethods.rst',
+        ],
+    ],
 ];
diff --git a/typo3/sysext/install/Configuration/ExtensionScanner/Php/PropertyPublicMatcher.php b/typo3/sysext/install/Configuration/ExtensionScanner/Php/PropertyPublicMatcher.php
index 78773493584b1a31787e39061aa86cc9b113b9b4..b24c1ddde8fbb62a3672aa81232bf57d87b903c4 100644
--- a/typo3/sysext/install/Configuration/ExtensionScanner/Php/PropertyPublicMatcher.php
+++ b/typo3/sysext/install/Configuration/ExtensionScanner/Php/PropertyPublicMatcher.php
@@ -376,4 +376,19 @@ return [
             'Deprecation-84295-UseServerRequestInterfaceInFileEditFileController.rst',
         ],
     ],
+    'TYPO3\CMS\Backend\FrontendBackendUserAuthentication->adminPanel' => [
+        'restFiles' => [
+            'Deprecation-84641-DeprecatedAdminPanelRelatedMethods.rst',
+        ],
+    ],
+    'TYPO3\CMS\Backend\FrontendBackendUserAuthentication->extAdminConfig' => [
+        'restFiles' => [
+            'Deprecation-84641-DeprecatedAdminPanelRelatedMethods.rst',
+        ],
+    ],
+    'TYPO3\CMS\Backend\FrontendBackendUserAuthentication->extAdmEnabled' => [
+        'restFiles' => [
+            'Deprecation-84641-DeprecatedAdminPanelRelatedMethods.rst',
+        ],
+    ],
 ];
diff --git a/typo3/sysext/lang/Resources/Private/Language/locallang_tsfe.xlf b/typo3/sysext/lang/Resources/Private/Language/locallang_tsfe.xlf
index a9652af872127ad418ed75b465d83cbe846c39ce..5bb39197cd3e7cf52a934ad4bc83c5a32af31585 100644
--- a/typo3/sysext/lang/Resources/Private/Language/locallang_tsfe.xlf
+++ b/typo3/sysext/lang/Resources/Private/Language/locallang_tsfe.xlf
@@ -9,6 +9,9 @@
 			<trans-unit id="adminPanelTitle">
 				<source>TYPO3 ADMIN PANEL</source>
 			</trans-unit>
+			<trans-unit id="preview">
+				<source>Preview</source>
+			</trans-unit>
 			<trans-unit id="publish">
 				<source>Publish</source>
 			</trans-unit>
diff --git a/typo3/sysext/workspaces/Classes/Authentication/PreviewUserAuthentication.php b/typo3/sysext/workspaces/Classes/Authentication/PreviewUserAuthentication.php
index 2ddc33e96f76c4787baa0cbc4265911150e2466c..807a18ee77b4fd2299680e4a3d4ce720fdc2b8d9 100644
--- a/typo3/sysext/workspaces/Classes/Authentication/PreviewUserAuthentication.php
+++ b/typo3/sysext/workspaces/Classes/Authentication/PreviewUserAuthentication.php
@@ -1,5 +1,6 @@
 <?php
 declare(strict_types = 1);
+
 namespace TYPO3\CMS\Workspaces\Authentication;
 
 /*
@@ -107,34 +108,4 @@ class PreviewUserAuthentication extends BackendUserAuthentication
     {
         return Permission::PAGE_SHOW;
     }
-
-    /**
-     * Stub to ensure that frontend editing is not possible as a preview user
-     *
-     * @return bool
-     */
-    public function initializeFrontendEdit()
-    {
-        return false;
-    }
-
-    /**
-     * Stub to ensure that frontend editing is not possible as a preview user
-     *
-     * @return bool
-     */
-    public function isFrontendEditingActive()
-    {
-        return false;
-    }
-
-    /**
-     * Stub to ensure that admin panel is not visible as a preview user
-     *
-     * @return bool
-     */
-    public function isAdminPanelVisible()
-    {
-        return false;
-    }
 }