diff --git a/composer.json b/composer.json
index 9c6118b7ceba77cba81d503c8c49e7f2905894df..c6f6f6c34e5ca5e694fc99b19607c88686d82a6b 100644
--- a/composer.json
+++ b/composer.json
@@ -16,6 +16,7 @@
             "Studip\\Cache\\": "lib/classes/cache/",
             "Studip\\Calendar\\": "lib/classes/calendar/",
             "Studip\\Forms\\": "lib/classes/forms/",
+            "Studip\\Rectors\\": "lib/Rectors/",
             "Studip\\": [
                 "lib/classes/",
                 "lib/exceptions/",
@@ -73,7 +74,8 @@
         "phpstan/phpstan": "^2.0",
         "symfony/var-dumper": "6.4.7",
         "maximebf/debugbar": "1.22.3",
-        "codeception/specify": "^2.0"
+        "codeception/specify": "^2.0",
+        "rector/rector": "2.0-rc1"
     },
     "require": {
         "php": "^8.1",
diff --git a/composer.lock b/composer.lock
index 7897e22c5d8504ec8ebc26cffd5441c808320524..7d6305153bfbda646b937b8daf4491fd4e061c2b 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "5bc2e4ef41517f46c14d02cfecdd95d9",
+    "content-hash": "07482a29c636bb9068a8e831addddca3",
     "packages": [
         {
             "name": "algo26-matthias/idna-convert",
@@ -7044,6 +7044,65 @@
             },
             "time": "2019-01-08T18:20:26+00:00"
         },
+        {
+            "name": "rector/rector",
+            "version": "2.0.0-rc1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/rectorphp/rector.git",
+                "reference": "75f78c934b79a5dd81415683600d85837edef86f"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/rectorphp/rector/zipball/75f78c934b79a5dd81415683600d85837edef86f",
+                "reference": "75f78c934b79a5dd81415683600d85837edef86f",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.4|^8.0",
+                "phpstan/phpstan": "^2.0.1"
+            },
+            "conflict": {
+                "rector/rector-doctrine": "*",
+                "rector/rector-downgrade-php": "*",
+                "rector/rector-phpunit": "*",
+                "rector/rector-symfony": "*"
+            },
+            "suggest": {
+                "ext-dom": "To manipulate phpunit.xml via the custom-rule command"
+            },
+            "bin": [
+                "bin/rector"
+            ],
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "Instant Upgrade and Automated Refactoring of any PHP code",
+            "keywords": [
+                "automation",
+                "dev",
+                "migration",
+                "refactoring"
+            ],
+            "support": {
+                "issues": "https://github.com/rectorphp/rector/issues",
+                "source": "https://github.com/rectorphp/rector/tree/2.0.0-rc1"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/tomasvotruba",
+                    "type": "github"
+                }
+            ],
+            "time": "2024-11-27T18:01:51+00:00"
+        },
         {
             "name": "sebastian/cli-parser",
             "version": "1.0.2",
@@ -8726,7 +8785,8 @@
     "aliases": [],
     "minimum-stability": "stable",
     "stability-flags": {
-        "edu-sharing/auth-plugin": 20
+        "edu-sharing/auth-plugin": 20,
+        "rector/rector": 5
     },
     "prefer-stable": false,
     "prefer-lowest": false,
diff --git a/lib/Rectors/Studip-6.0-Set.php b/lib/Rectors/Studip-6.0-Set.php
new file mode 100644
index 0000000000000000000000000000000000000000..ca019b255472a3251442264a2ddd697124b5403d
--- /dev/null
+++ b/lib/Rectors/Studip-6.0-Set.php
@@ -0,0 +1,51 @@
+<?php
+use Rector\Config\RectorConfig;
+use Rector\Renaming\Rector\FuncCall\RenameFunctionRector;
+use Rector\Renaming\Rector\Name\RenameClassRector;
+use Studip\Rectors\Studip60\RemoveFunctionCallRector;
+use Studip\Rectors\Studip60\RemoveIncludesRector;
+
+return RectorConfig::configure()
+    ->withRules([
+        Studip\Rectors\Studip60\RemoveGetConfigRector::class,
+        Studip\Rectors\Studip60\RemoveSidebarMethodsRector::class
+    ])
+    ->withConfiguredRule(RenameFunctionRector::class, [
+        'studip_json_decode' => 'json_decode',
+        'studip_json_encode' => 'json_encode',
+    ])
+    ->withConfiguredRule(RemoveIncludesRector::class, [
+        'vendor/flexi',
+        'vendor/trails',
+        'app/controllers/authenticated_controller.php',
+        'app/controllers/plugin_controller.php',
+        'app/controllers/studip_controller.php',
+        'app/controllers/studip_controller_properties_trait.php',
+        'app/controllers/studip_response.php',
+    ])
+    ->withConfiguredRule(RemoveFunctionCallRector::class, [
+        'smile',
+        'transformBeforeSave',
+    ])
+    ->withConfiguredRule(RenameClassRector::class, [
+        'Flexi_PhpTemplate' => 'Flexi\PhpTemplate',
+        'Flexi_Template' => 'Flexi\Template',
+        'Flexi_TemplateFactory' => 'Flexi\Factory',
+
+        'StudipCacheFactory' => 'Studip\Cache\Factory',
+        'StudipCache' => 'Studip\Cache\Cache',
+        'StudipDbCache' => 'Studip\Cache\DbCache',
+
+        'Trails_Controller' => 'Trails\Controller',
+        'Trails_Dispatcher' => 'Trails\Dispatcher',
+        'Trails_Exception' => 'Trails\Exception',
+        'Trails_Flash' => 'Trails\Flash',
+        'Trails_Inflector' => 'Trails\Inflector',
+        'Trails_Response' => 'Trails\Response',
+        'Trails_DoubleRenderError' => 'Trails\Exceptions\DoubleRenderError',
+        'Trails_MissingFile' => 'Trails\Exceptions\MissingFile',
+        'Trails_RoutingError' => 'Trails\Exceptions\RoutingError',
+        'Trails_SessionRequired' => 'Trails\Exceptions\SessionRequiredException',
+        'Trails_UnknownAction' => 'Trails\Exceptions\UnknownAction',
+        'Trails_UnknownController' => 'Trails\Exceptions\UnknownController',
+    ]);
diff --git a/lib/Rectors/Studip60/RemoveFunctionCallRector.php b/lib/Rectors/Studip60/RemoveFunctionCallRector.php
new file mode 100644
index 0000000000000000000000000000000000000000..1ee6180fc8cad555dfa0c1bdba0a106b77672e3c
--- /dev/null
+++ b/lib/Rectors/Studip60/RemoveFunctionCallRector.php
@@ -0,0 +1,43 @@
+<?php
+declare(strict_types=1);
+
+namespace Studip\Rectors\Studip60;
+
+use PhpParser\Node;
+use PhpParser\Node\Expr\FuncCall;
+use Rector\Contract\Rector\ConfigurableRectorInterface;
+use Rector\Rector\AbstractRector;
+use RectorPrefix202411\Webmozart\Assert\Assert;
+
+final class RemoveFunctionCallRector extends AbstractRector implements ConfigurableRectorInterface
+{
+    private array $removes = [];
+
+    public function getNodeTypes(): array
+    {
+        return [FuncCall::class];
+    }
+
+    public function refactor(Node $node)
+    {
+        if (!$this->isNames($node, $this->removes)) {
+            return null;
+        }
+
+        if (!isset($node->args[0])) {
+            return null;
+        }
+
+        return $node->args[0]->value;
+    }
+
+    /**
+     * @param mixed[] $configuration
+     */
+    public function configure(array $configuration): void
+    {
+        Assert::allString($configuration);
+        Assert::isList($configuration);
+        $this->removes = $configuration;
+    }
+}
diff --git a/lib/Rectors/Studip60/RemoveGetConfigRector.php b/lib/Rectors/Studip60/RemoveGetConfigRector.php
new file mode 100644
index 0000000000000000000000000000000000000000..da77a269ff9c8337f2e21ae2e1e913751a6a4d5d
--- /dev/null
+++ b/lib/Rectors/Studip60/RemoveGetConfigRector.php
@@ -0,0 +1,59 @@
+<?php
+namespace Studip\Rectors\Studip60;
+
+use PhpParser\Node;
+use PhpParser\Node\Expr\FuncCall;
+use Rector\PhpParser\Node\Value\ValueResolver;
+use Rector\Rector\AbstractRector;
+use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
+use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
+
+final class RemoveGetConfigRector extends AbstractRector
+{
+    private ValueResolver $valueResolver;
+
+    public function __construct(ValueResolver $valueResolver)
+    {
+        $this->valueResolver = $valueResolver;
+    }
+
+    public function getRuleDefinition(): RuleDefinition
+    {
+        return new RuleDefinition(
+            'Replace calls to function "get_config()" with calls to "Config::get()->getValue()',
+            [
+                new CodeSample(
+                    '$value = get_config(\'FOO_BAR\');',
+                    '$value = Config::get()->getValue(\'FOO_BAR\');'
+                )
+            ]
+        );
+    }
+
+    public function getNodeTypes(): array
+    {
+        return [FuncCall::class];
+    }
+
+    /**
+     * @param FuncCall $node
+     */
+    public function refactor(Node $node)
+    {
+        if (!$this->isName($node->name, 'get_config')) {
+            return $node;
+        }
+
+        return $this->nodeFactory->createMethodCall(
+            $this->nodeFactory->createStaticCall(
+                \Config::class,
+                'get'
+            ),
+            'getValue',
+            array_map(
+                fn($arg) => $this->valueResolver->getValue($arg),
+                $node->getArgs()
+            )
+        );
+    }
+}
diff --git a/lib/Rectors/Studip60/RemoveIncludesRector.php b/lib/Rectors/Studip60/RemoveIncludesRector.php
new file mode 100644
index 0000000000000000000000000000000000000000..8ba8f92dd5008f040985027053fe57dfeaeb7640
--- /dev/null
+++ b/lib/Rectors/Studip60/RemoveIncludesRector.php
@@ -0,0 +1,60 @@
+<?php
+declare(strict_types=1);
+
+namespace Studip\Rectors\Studip60;
+
+use PhpParser\Node;
+use PhpParser\Node\Expr\Include_;
+use PhpParser\Node\Scalar\String_;
+use PhpParser\Node\Stmt\Expression;
+use PhpParser\NodeVisitor;
+use Rector\Contract\Rector\ConfigurableRectorInterface;
+use Rector\Rector\AbstractRector;
+use RectorPrefix202411\Webmozart\Assert\Assert;
+
+final class RemoveIncludesRector extends AbstractRector implements ConfigurableRectorInterface
+{
+    private array $removeIncludes = [];
+
+    public function getNodeTypes(): array
+    {
+        return [Expression::class];
+    }
+
+    /**
+     * @param Expression $node
+     */
+    public function refactor(Node $node): ?int
+    {
+        if (!$node->expr instanceof Include_) {
+            return null;
+        }
+
+        if (!$this->matches($node->expr->expr)) {
+            return null;
+        }
+
+        return self::REMOVE_NODE;
+    }
+
+    /**
+     * @param mixed[] $configuration
+     */
+    public function configure(array $configuration): void
+    {
+        Assert::allString($configuration);
+        Assert::isList($configuration);
+        $this->removeIncludes = $configuration;
+    }
+
+    private function matches(String_ $expr): bool
+    {
+        foreach ($this->removeIncludes as $removeInclude) {
+            if (str_contains($expr->value, $removeInclude)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}
diff --git a/lib/Rectors/Studip60/RemoveSidebarMethodsRector.php b/lib/Rectors/Studip60/RemoveSidebarMethodsRector.php
new file mode 100644
index 0000000000000000000000000000000000000000..52256880848836d29a9d81ad5ab495ca5dc91f4e
--- /dev/null
+++ b/lib/Rectors/Studip60/RemoveSidebarMethodsRector.php
@@ -0,0 +1,61 @@
+<?php
+// TODO: Assignment!
+declare(strict_types=1);
+
+namespace Studip\Rectors\Studip60;
+
+use PhpParser\Node;
+use PhpParser\Node\Expr\StaticCall;
+use PhpParser\Node\Stmt\Expression;
+use PhpParser\NodeVisitor;
+use Rector\Rector\AbstractRector;
+use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
+use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
+
+final class RemoveSidebarMethodsRector extends AbstractRector
+{
+    public function getRuleDefinition(): RuleDefinition
+    {
+        return new RuleDefinition(
+            'Remove deprecated sidebar methods',
+            [
+                new CodeSample(
+                    <<<'CODE_SAMPLE'
+Sidebar::setImage('foo.gif');
+$foo = Sidebar::getImage();
+Sidebar::removeImage();
+CODE_SAMPLE,
+                    ''
+                )
+            ]
+        );
+    }
+
+    public function getNodeTypes(): array
+    {
+        return [Expression::class];
+    }
+
+    /**
+     * @param Expression $node
+     * @return int|null
+     */
+    public function refactor(Node $node): ?int
+    {
+        $expr = $node->expr;
+        if (!$expr instanceof StaticCall) {
+            return null;
+        }
+
+        if (!$this->isName($expr->class, 'Sidebar')) {
+            return null;
+        }
+
+        $methodsToRemove = ['setImage', 'getImage', 'removeImage'];
+        if ($this->isNames($expr->name, $methodsToRemove)) {
+            return NodeVisitor::REMOVE_NODE;
+        }
+
+        return null;
+    }
+}
diff --git a/rector-test.php b/rector-test.php
new file mode 100644
index 0000000000000000000000000000000000000000..046b79a519a7c041a82e60aaee7cbb568a1a73f1
--- /dev/null
+++ b/rector-test.php
@@ -0,0 +1,53 @@
+<?php
+
+include 'vendor/flexi/lib/flexi.php';
+require_once 'vendor/trails/trails.php';
+
+include_once 'app/controllers/studip_controller.php';
+require 'app/controllers/plugin_controller.php';
+require 'app/controllers/studip_controller_properties_trait.php';
+require 'app/controllers/studip_response.php';
+
+$foo = get_config('FOO_BAR');;
+$foo = studip_json_encode($foo);
+$foo = studip_json_decode($foo, true);
+echo transformBeforeSave(smile($foo));
+
+Sidebar::setImage('foo.gif');
+$bar = Sidebar::getImage();
+Sidebar::removeImage();
+
+/** @var StudipCache $cache */
+$cache = StudipCacheFactory::getCache();
+if ($cache instanceof StudipDbCache) {
+    echo 'Cached in database';
+}
+
+$factory = new Flexi_TemplateFactory(__DIR__);
+/** @var Flexi_Template $template */
+$template = $factory->open('foo.php');
+if ($template instanceof Flexi_PhpTemplate) {
+    echo 'Template is php';
+}
+
+try {
+    $dispatcher = new Trails_Dispatcher('', '', '');
+    $controller = new Trails_Controller($dispatcher);
+    $flash = new Trails_Flash();
+    $inflector = new Trails_Inflector();
+} catch (Trails_DoubleRenderError $e) {
+    echo 'double render';
+} catch (Trails_MissingFile $e) {
+    echo 'missing file';
+} catch (Trails_RoutingError $e) {
+    echo 'routing error';
+} catch (Trails_SessionRequiredException $e) {
+    echo 'session required';
+} catch (Trails_UnknownAction $e) {
+    echo 'unknown action';
+} catch (Trails_UnknownController $e) {
+    echo 'unknown controller';
+} catch (Trails_Exception $e) {
+    echo 'some exception';
+}
+
diff --git a/rector.php b/rector.php
new file mode 100644
index 0000000000000000000000000000000000000000..4f025745635becaa5acd33592a44052cf4b61a29
--- /dev/null
+++ b/rector.php
@@ -0,0 +1,29 @@
+<?php
+
+declare(strict_types=1);
+
+use Rector\Config\RectorConfig;
+
+return RectorConfig::configure()
+    ->withPaths([
+        __DIR__ . '/app/controllers',
+        __DIR__ . '/cli',
+        __DIR__ . '/config',
+        __DIR__ . '/db',
+        __DIR__ . '/lib',
+        __DIR__ . '/public/*.php',
+        __DIR__ . '/tests',
+    ])
+    ->withSkip([
+        __DIR__ . '/tests/_data',
+        __DIR__ . '/tests/_support',
+    ])
+    ->withSets([
+        __DIR__ . '/lib/Rectors/Studip-6.0-Set.php'
+    ])
+    // uncomment to reach your current PHP version
+    ->withPhpSets()
+//    ->withTypeCoverageLevel(0)
+//    ->withDeadCodeLevel(0)
+//    ->withCodeQualityLevel(0)
+;