diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..f191e45b65b82cca2df6838601e4026e77fcd130
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,25 @@
+image: registry.edugit.org/teckids/team-sysadmin/docker-images/python-pimped:master
+
+stages:
+      - test
+      - build
+
+variables:
+  GIT_SUBMODULE_STRATEGY: recursive
+  PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
+  FF_NETWORK_PER_BUILD: "true"
+
+cache:
+  key:
+    files:
+      - poetry.lock
+      - pyproject.toml
+  paths:
+    - .cache/pip
+    - .tox
+
+include:
+    - project: "AlekSIS/official/AlekSIS"
+      file: /ci/test.yml
+    - project: "AlekSIS/official/AlekSIS"
+      file: /ci/build_dist.yml
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000000000000000000000000000000000000..26f052e532b1c37d9d2626dde1079d4520245871
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,82 @@
+[tox]
+skipsdist = True
+skip_missing_interpreters = true
+envlist = py37,py38
+
+[testenv]
+whitelist_externals = poetry
+		      sudo
+skip_install = true
+envdir = {toxworkdir}/globalenv
+commands_pre =
+     - poetry install
+commands =
+    - poetry run pytest --cov=. {posargs} aleksis/
+
+[testenv:selenium]
+setenv =
+    TEST_SCREENSHOT_PATH = {env:TEST_SCREENSHOT_PATH:.tox/screenshots}
+    TEST_SELENIUM_HUB = {env:TEST_SELENIUM_HUB:http://127.0.0.1:4444/wd/hub}
+    TEST_SELENIUM_BROWSERS = {env:TEST_SELENIUM_BROWSERS:chrome,firefox}
+    TEST_HOST = {env:TEST_HOST:172.17.0.1}
+
+[testenv:lint]
+commands =
+    - poetry run black --check --diff aleksis/ --exclude "migrations"
+    - poetry run isort -c --diff --stdout -rc -s migrations aleksis/
+    - poetry run flake8 {posargs} --exclude-from-doctest migrations aleksis/
+
+[testenv:security]
+commands =
+    poetry show --no-dev
+    poetry run safety check --full-report
+
+[testenv:build]
+commands_pre =
+commands = poetry build
+
+[testenv:docs]
+commands = poetry run make -C docs/ html {posargs}
+
+[testenv:reformat]
+commands =
+    poetry run isort -rc aleksis/
+    poetry run black aleksis/
+
+[flake8]
+max_line_length = 100
+exclude = migrations,tests
+ignore = BLK100,E203,E231,W503,D100,D101,D102,D103,D104,D105,D106,D107,RST215,RST214,F821,F841,S106,T100,T101,DJ05
+
+[isort]
+line_length = 100
+multi_line_output = 3
+include_trailing_comma = 1
+use_parantheses = 1
+default_section = THIRDPARTY
+known_first_party = aleksis
+known_django = django
+sections = FUTURE,STDLIB,DJANGO,THIRDPARTY,FIRSTPARTY,LOCALFOLDER
+
+[mypy]
+plugins = mypy_django_plugin.main
+python_version = 3.8
+platform = linux
+show_column_numbers = True
+follow_imports = skip
+ignore_missing_imports = True
+cache_dir = /dev/null
+
+[mypy.plugins.django-stubs]
+django_settings_module = aleksis.core.settings
+
+[pytest]
+DJANGO_SETTINGS_MODULE = aleksis.core.settings
+junit_family = legacy
+
+[coverage:run]
+omit =
+    */migrations/*
+    */tests/*
+    .tox/*
+    manage.py