diff --git a/base.txt b/base.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/lectures/admin.py b/lectures/admin.py
index e99d3583833c46a391558bbd24a1a94144b24848..565bdb47a030c76c85cca24ba0b7fc117b909d5d 100644
--- a/lectures/admin.py
+++ b/lectures/admin.py
@@ -1,5 +1,6 @@
 from django.contrib import admin
 from markdownx.admin import MarkdownxModelAdmin
+from modelclone import ClonableModelAdmin
 
 from .forms import LectureGroupTypeFormset
 from .models import (
@@ -44,7 +45,7 @@ class LectureGroupTypeInline(admin.StackedInline):
     extra = 1
 
 
-class LectureAdmin(MarkdownxModelAdmin):
+class LectureAdmin(ClonableModelAdmin, MarkdownxModelAdmin):
     inlines = (
         LectureGroupTypeInline,
         LectureRecordingInline,
@@ -55,6 +56,21 @@ class LectureAdmin(MarkdownxModelAdmin):
     search_fields = ("name", "description")
     readonly_fields = ("rsvp_users",)
 
+    fieldsets = (
+        (
+            None,
+            {
+                "fields": [
+                    "timestamp",
+                    "category",
+                    "name",
+                    "description",
+                ]
+            },
+        ),
+        ("Registrovaní účastníci", {"fields": ["rsvp_users"]}),
+    )
+
     list_display = (
         "name",
         "timestamp",
diff --git a/lectures/migrations/0028_alter_lecture_rsvp_users.py b/lectures/migrations/0028_alter_lecture_rsvp_users.py
new file mode 100644
index 0000000000000000000000000000000000000000..767bb936cacecee53496f0adb85dbc9df04e7e61
--- /dev/null
+++ b/lectures/migrations/0028_alter_lecture_rsvp_users.py
@@ -0,0 +1,20 @@
+# Generated by Django 5.0.2 on 2024-02-26 16:02
+
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('lectures', '0027_alter_lecturecategory_options'),
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='lecture',
+            name='rsvp_users',
+            field=models.ManyToManyField(blank=True, related_name='rsvp_lectures', to=settings.AUTH_USER_MODEL, verbose_name='Registrovaní účastníci'),
+        ),
+    ]
diff --git a/lectures/models.py b/lectures/models.py
index cb058fafb6bb703416a2f0fa79a34e69a6183ab4..1979f4eb059ff89f2e7aefc0768c47d94baefe3f 100644
--- a/lectures/models.py
+++ b/lectures/models.py
@@ -168,7 +168,7 @@ class Lecture(NameStrMixin, models.Model):
         "users.User",
         blank=True,
         related_name="rsvp_lectures",
-        verbose_name="Zaregistrovaní uživatelé",
+        verbose_name="Registrovaní účastníci",
     )
 
     # Settings
diff --git a/lectures/templates/lectures/view_group_lectures.html b/lectures/templates/lectures/view_group_lectures.html
index 8b742c72152f7f1842cddc4e1b705832cb437fe6..3195496fe75d8bfbe4ec2648c252ae15bd5ba50f 100644
--- a/lectures/templates/lectures/view_group_lectures.html
+++ b/lectures/templates/lectures/view_group_lectures.html
@@ -19,12 +19,17 @@
 
     <div class="__js-root">
         <ui-view-provider
-            :initial="{current_lectures: false, calendar: false, recordings: true}"
+            :initial="{current_lectures: false, timeline: true, recordings: false}"
             :sync-location="true"
             v-slot="{ isCurrentView, toggleView }"
         >
             <div class="flex justify-center mb-10">
                 <div class="switch overflow-x-auto">
+                    <a
+                        @click="toggleView('timeline')"
+                        class="switch__item whitespace-nowrap"
+                        :class="{'switch__item--active': isCurrentView('timeline')}"
+                    >Časová osa</a>
                     <a
                         @click="toggleView('recordings')"
                         class="switch__item whitespace-nowrap"
@@ -35,11 +40,6 @@
                         class="switch__item whitespace-nowrap"
                         :class="{'switch__item--active': isCurrentView('current_lectures')}"
                     >Aktuálně</a>
-                    <a
-                        @click="toggleView('timeline')"
-                        class="switch__item whitespace-nowrap"
-                        :class="{'switch__item--active': isCurrentView('timeline')}"
-                    >Časová osa</a>
                 </div>
             </div>
             <div>
diff --git a/requirements/base.in b/requirements/base.in
new file mode 100644
index 0000000000000000000000000000000000000000..9b9f73000b15ec1cf1a1d459e55d7baba3367361
--- /dev/null
+++ b/requirements/base.in
@@ -0,0 +1,19 @@
+django
+django-admin-index
+django-admin-interface
+django-database-url
+django-dbsettings
+django-downloadview
+django-markdownx
+django-ordered-model
+django-webpack-loader
+pirates
+django-markdownx
+django-environ
+django-http-exceptions
+django-modelclone-next
+gql[requests]
+requests
+PyJWT
+Pillow
+psycopg2-binary
diff --git a/requirements/base.txt b/requirements/base.txt
index 9115d8a6957a9722b87f776de8bac0d47f6be0e7..c5f8664f47491e251b49d134665208735f52bb37 100644
--- a/requirements/base.txt
+++ b/requirements/base.txt
@@ -1,18 +1,111 @@
-django==4.1.4
-django-admin-index==2.0.2
-django-admin-interface==0.24.2
+#
+# This file is autogenerated by pip-compile with Python 3.11
+# by the following command:
+#
+#    pip-compile base.in
+#
+anyio==4.3.0
+    # via gql
+asgiref==3.7.2
+    # via django
+backoff==2.2.1
+    # via gql
+certifi==2024.2.2
+    # via requests
+cffi==1.16.0
+    # via cryptography
+charset-normalizer==3.3.2
+    # via requests
+cryptography==42.0.5
+    # via
+    #   josepy
+    #   mozilla-django-oidc
+    #   pyopenssl
+django==5.0.2
+    # via
+    #   -r base.in
+    #   django-admin-index
+    #   django-database-url
+    #   django-downloadview
+    #   django-http-exceptions
+    #   django-markdownx
+    #   mozilla-django-oidc
+django-admin-index==3.1.0
+    # via -r base.in
+django-admin-interface==0.28.5
+    # via -r base.in
+django-colorfield==0.11.0
+    # via django-admin-interface
 django-database-url==1.0.3
+    # via -r base.in
 django-dbsettings==1.3.0
+    # via -r base.in
 django-downloadview==2.3.0
-django-markdownx==4.0.0b1
-django-ordered-model==3.7.1
-django-webpack-loader==1.8.0
-pirates==0.6.0
-django-markdownx==4.0.0b1
-django-environ==0.9.0
+    # via -r base.in
+django-environ==0.11.2
+    # via -r base.in
 django-http-exceptions==1.4.0
-gql[requests]==3.4.1
+    # via -r base.in
+django-markdownx==4.0.7
+    # via -r base.in
+django-modelclone-next==0.8.2
+    # via -r base.in
+django-ordered-model==3.7.4
+    # via
+    #   -r base.in
+    #   django-admin-index
+django-webpack-loader==3.0.1
+    # via -r base.in
+gql[requests]==3.5.0
+    # via -r base.in
+graphql-core==3.2.3
+    # via gql
+idna==3.6
+    # via
+    #   anyio
+    #   requests
+    #   yarl
+josepy==1.14.0
+    # via mozilla-django-oidc
+markdown==3.5.2
+    # via django-markdownx
+mozilla-django-oidc==3.0.0
+    # via pirates
+multidict==6.0.5
+    # via yarl
+pillow==10.2.0
+    # via
+    #   -r base.in
+    #   django-colorfield
+    #   django-markdownx
+pirates==0.7.0
+    # via -r base.in
+psycopg2-binary==2.9.9
+    # via -r base.in
+pycparser==2.21
+    # via cffi
+pyjwt==2.8.0
+    # via -r base.in
+pyopenssl==24.0.0
+    # via josepy
+python-slugify==8.0.4
+    # via django-admin-interface
 requests==2.31.0
-PyJWT==2.6.0
-Pillow==9.5.0
-psycopg2-binary==2.9.5
+    # via
+    #   -r base.in
+    #   django-downloadview
+    #   gql
+    #   mozilla-django-oidc
+    #   requests-toolbelt
+requests-toolbelt==1.0.0
+    # via gql
+sniffio==1.3.1
+    # via anyio
+sqlparse==0.4.4
+    # via django
+text-unidecode==1.3
+    # via python-slugify
+urllib3==2.2.1
+    # via requests
+yarl==1.9.4
+    # via gql
diff --git a/requirements/production.in b/requirements/production.in
new file mode 100644
index 0000000000000000000000000000000000000000..e52364aa0dd48052cd1ce92bfd314e886c144e09
--- /dev/null
+++ b/requirements/production.in
@@ -0,0 +1,2 @@
+gunicorn
+whitenoise
diff --git a/requirements/production.txt b/requirements/production.txt
index ce5169e4440b67843ee5d28199ed63e0d8323cfc..f7490d5928de629ccd3aa5ee6c3692783a51d6d6 100644
--- a/requirements/production.txt
+++ b/requirements/production.txt
@@ -1,2 +1,12 @@
-gunicorn==20.1.0
-whitenoise==6.3.0
+#
+# This file is autogenerated by pip-compile with Python 3.11
+# by the following command:
+#
+#    pip-compile production.in
+#
+gunicorn==21.2.0
+    # via -r production.in
+packaging==23.2
+    # via gunicorn
+whitenoise==6.6.0
+    # via -r production.in
diff --git a/shared/locale/cs_CZ/LC_MESSAGES/django.mo b/shared/locale/cs_CZ/LC_MESSAGES/django.mo
new file mode 100644
index 0000000000000000000000000000000000000000..675f7c4f5df3718188bad466d47e6ebce9fff765
Binary files /dev/null and b/shared/locale/cs_CZ/LC_MESSAGES/django.mo differ
diff --git a/shared/locale/cs_CZ/LC_MESSAGES/django.po b/shared/locale/cs_CZ/LC_MESSAGES/django.po
new file mode 100644
index 0000000000000000000000000000000000000000..5b50947dee287f8c6505242eeb3a74b02720c859
--- /dev/null
+++ b/shared/locale/cs_CZ/LC_MESSAGES/django.po
@@ -0,0 +1,26 @@
+# Czech translation of django-guardian.
+# This file is distributed under the same license as django-guardian's package.
+# Translator: Tomáš Valenta <tomas@imaniti.org>, 2023.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: django-guardian 1.2\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-11-09 19:00+0100\n"
+"PO-Revision-Date: 2023-11-09 19:00-0600\n"
+"Last-Translator: Tomáš Valenta <tomas@imaniti.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: cs\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+"X-Translated-Using: django-rosetta 0.7.3\n"
+
+#: admin.py:21
+msgid "Duplicate"
+msgstr "Duplikovat"
+
+#: admin.py:70
+#, python-brace-format
+msgid "{name} object with primary key {key} does not exist."
+msgstr "Objekt {name} s klíčem {key} neexistuje."
diff --git a/ucebnice/settings/base.py b/ucebnice/settings/base.py
index 792f93dfc6b8cc8e2d71bfd935e081dee56ecbf0..9df63b06ff7b0ebb4bc1ff9fc62a268b000efc50 100644
--- a/ucebnice/settings/base.py
+++ b/ucebnice/settings/base.py
@@ -51,6 +51,7 @@ INSTALLED_APPS = [
     "django.contrib.sessions",
     "django.contrib.messages",
     "django.contrib.staticfiles",
+    "modelclone",
     "dbsettings",
     "markdownx",
     "pirates",