diff --git a/.pylintrc b/.pylintrc
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/management/forms.py b/management/forms.py
index 5b4ffad0ebfaef2139afaf724075e5411e477378..bd2ff7d0c4718e8a5f832021fa020c7ddc840681 100644
--- a/management/forms.py
+++ b/management/forms.py
@@ -62,13 +62,15 @@ class TemplateStringForm:
         checks if the cleaned_text fails when formatted on the test_data.
         """
         test_data_dict = {i: "" for i in test_data}
-        cleaned_text = self.cleaned_data[field]
+        cleaned_text = self.cleaned_data[field]  # pylint: disable=no-member
         try:
             cleaned_text.format(**test_data_dict)
         except (KeyError, ValueError, IndexError):
             x = re.findall(r"\{\w*\}", cleaned_text)
             test_data = set(x) - {f"{{{i}}}" for i in test_data}
-            self.add_error(field, "The following variables are not allowed: " + ", ".join(test_data))
+            self.add_error(  # pylint: disable=no-member
+                field, "The following variables are not allowed: " + ", ".join(test_data)
+            )
         return cleaned_text
 
 
diff --git a/management/urls.py b/management/urls.py
index 1a5779b25327b884487f5baedef5f43b9400358b..37ea99bd141b24227f0420092af693d3fd5a9eb9 100644
--- a/management/urls.py
+++ b/management/urls.py
@@ -2,7 +2,6 @@ from django.contrib.auth import views as auth_views
 from django.urls import path
 from prometheus_client import Gauge
 
-import vote.views
 from management import views
 from management.models import ElectionManager
 from vote.models import Election, Session
diff --git a/pyproject.toml b/pyproject.toml
index 5305c433817d53cb8f78230175a1619821a20372..4a99030027e5280a30d319720dbf8be12e33f516 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -7,49 +7,56 @@ build-backend = 'setuptools.build_meta'
 
 [tool.pylint]
 [tool.pylint.master]
-ignore = ['migrations', 'settings.py']
-jobs = 1
+ignore = ['migrations', 'settings.py', 'docs']
+jobs = 4
 load-plugins = 'pylint_django'
 django-settings-module = 'wahlfang.settings.development'
 
 [tool.pylint.'MESSAGES CONTROL']
 disable = [
-    'print-statement',
-    'missing-function-docstring',
-    'missing-module-docstring',
-    'missing-class-docstring',
-    'line-too-long',
-    'invalid-name',
+    'R',
+    'C',
     'unused-argument',
-    'too-many-locals',
-    'too-many-statements',
-    'too-many-instance-arguments',
-    'too-few-public-methods',
-    'too-many-arguments',
-    'too-many-instance-attributes',
-    'too-many-branches',
-    'too-many-lines',
-    'too-many-public-methods',
-    'bad-indentation',
-    'bad-continuation',
-    'import-error',
-    'wildcard-import',
-    'no-self-use',
-    'duplicate-code',
-    'wrong-import-position',
-    'no-member',
-    'unused-import'
+    'fixme'
+    #'print-statement',
+    #'missing-function-docstring',
+    #'missing-module-docstring',
+    #'missing-class-docstring',
+    #'line-too-long',
+    #'invalid-name',
+    #'too-many-locals',
+    #'too-many-statements',
+    #'too-many-instance-arguments',
+    #'too-few-public-methods',
+    #'too-many-arguments',
+    #'too-many-instance-attributes',
+    #'too-many-branches',
+    #'too-many-lines',
+    #'too-many-public-methods',
+    #'bad-indentation',
+    #'bad-continuation',
+    #'import-error',
+    #'wildcard-import',
+    #'no-self-use',
+    #'duplicate-code',
+    #'wrong-import-position',
+    #'no-member',
+    #'unused-import',
+    #'missing-module-docstring',
+    #'missing-class-docstring',
+    #'missing-function-docstring'
 ]
 
 [tool.mypy]
 plugins = [
     'mypy_django_plugin.main'
 ]
+exclude = 'docs'
 ignore_missing_imports = true
 pretty = true
 
-#[tool.mypy.plugins.'django-stubs']  # FIXME: this does not work with toml apparently
-#django_settings_module = 'wahlfang.settings.development'
+[tool.django-stubs]
+django_settings_module = 'wahlfang.settings.development'
 
 [tool.'mypy-*'.'migrations.*']
 ignore_errors = true
diff --git a/requirements_dev.txt b/requirements_dev.txt
index 9e9bc72c16f089869d147d9496bb583521e137f5..ba090f05a41eeadce07da2e0bbdc63196daa2825 100644
--- a/requirements_dev.txt
+++ b/requirements_dev.txt
@@ -1,5 +1,5 @@
 bandit==1.6.2
-pylint==2.8
+pylint==2.11.1
 pylint-django~=2.4
 django-cors-headers~=3.7.0
 django-stubs
diff --git a/setup.py b/setup.py
index f9eaf86d85cfc8758428f2b8dcf384ee2bd54310..0cf9fb764fecc35102a974f7e320266fe8eb9141 100644
--- a/setup.py
+++ b/setup.py
@@ -1,6 +1,6 @@
 import os
 import shutil
-from subprocess import run
+from subprocess import run  # nosec
 
 from setuptools import setup
 
@@ -13,7 +13,7 @@ os.chdir(ui_dir)
 static_dir = os.path.join(ui_dir, 'static')
 if os.path.exists(static_dir):
     shutil.rmtree(static_dir)
-run(['yarn', 'build'], check=True)
+run(['yarn', 'build'], check=True)  # nosec
 os.chdir(curr_dir)
 
 setup()
diff --git a/vote/models.py b/vote/models.py
index 22c5811a4c3831dc69e7696248ce87c51456b16d..d139ef5dd029ba8e5134f2231e7f8851dbecd03f 100644
--- a/vote/models.py
+++ b/vote/models.py
@@ -487,9 +487,9 @@ class Application(models.Model):
              update_fields=None):
         if self.avatar and self._old_avatar != self.avatar:
             # remove old file
-            if self._old_avatar and os.path.isfile(self._old_avatar.path):
+            if self._old_avatar and os.path.isfile(self._old_avatar.path):  # pylint: disable=E1101
                 # let's not play russian roulette
-                path = os.path.normpath(self._old_avatar.path)
+                path = os.path.normpath(self._old_avatar.path)  # pylint: disable=E1101
                 if path.startswith(os.path.join(settings.MEDIA_ROOT, 'avatars')):
                     os.remove(path)
 
diff --git a/wahlfang_api/admin.py b/wahlfang_api/admin.py
index 8c38f3f3dad51e4585f3984282c2a4bec5349c1e..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
--- a/wahlfang_api/admin.py
+++ b/wahlfang_api/admin.py
@@ -1,3 +0,0 @@
-from django.contrib import admin
-
-# Register your models here.
diff --git a/wahlfang_api/serializers.py b/wahlfang_api/serializers.py
index 562c35ee3bcf3fcb628885b78679e67f2fe5fd8e..fb18556341e367c1ae020967dc7d21ad36fa0cb2 100644
--- a/wahlfang_api/serializers.py
+++ b/wahlfang_api/serializers.py
@@ -1,6 +1,6 @@
 from django.conf import settings
 from django.contrib.auth import authenticate
-from rest_framework import serializers, fields
+from rest_framework import serializers
 from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
 from rest_framework_simplejwt.tokens import RefreshToken
 
diff --git a/wahlfang_api/tests.py b/wahlfang_api/tests.py
index 7ce503c2dd97ba78597f6ff6e4393132753573f6..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
--- a/wahlfang_api/tests.py
+++ b/wahlfang_api/tests.py
@@ -1,3 +0,0 @@
-from django.test import TestCase
-
-# Create your tests here.
diff --git a/wahlfang_api/views.py b/wahlfang_api/views.py
index 710b3f31dbb788039ab63a2b0419c92902e4b792..a8184c04ad23dbc9abe78c0174aca092eff8dc89 100644
--- a/wahlfang_api/views.py
+++ b/wahlfang_api/views.py
@@ -8,7 +8,6 @@ from rest_framework.throttling import AnonRateThrottle
 from rest_framework_simplejwt.views import TokenViewBase
 
 from vote.forms import VoteForm
-from management.forms import AddSessionForm
 from vote.models import Election, Voter, Application, Session
 from wahlfang_api.authentication import IsVoter, IsElectionManager, ElectionManagerJWTAuthentication, \
     VoterJWTAuthentication