diff --git a/profile/migrations/0001_squashed.py b/profile/migrations/0001_squashed.py
new file mode 100644
index 0000000000000000000000000000000000000000..e0e3632cfc0b65106bc182cc368695102da9a7e7
--- /dev/null
+++ b/profile/migrations/0001_squashed.py
@@ -0,0 +1,31 @@
+# Generated by Django 2.2.12 on 2020-11-21 01:34
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    replaces = [('profile', '0001_initial'), ('profile', '0002_auto_20171129_1828'), ('profile', '0003_auto_20171213_1737')]
+
+    initial = True
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Profile',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('cba_username', models.CharField(blank=True, help_text='Your username in CBA. This is necessary for uploading files to your account.', max_length=60, verbose_name='CBA Username')),
+                ('cba_user_token', models.CharField(blank=True, help_text='The CBA upload token for your account. This is NOT your password which you use to log into CBA!', max_length=255, verbose_name='CBA Token')),
+                ('user', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL)),
+            ],
+            options={
+                'db_table': 'profile',
+            },
+        ),
+    ]
diff --git a/program/migrations/0001_squashed.py b/program/migrations/0001_squashed.py
new file mode 100644
index 0000000000000000000000000000000000000000..4cb32c530694e42fb9a26896c1c84ecd552c3bf4
--- /dev/null
+++ b/program/migrations/0001_squashed.py
@@ -0,0 +1,342 @@
+# Generated by Django 2.2.12 on 2020-11-21 01:34
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+import tinymce.models
+import versatileimagefield.fields
+
+
+class Migration(migrations.Migration):
+
+    replaces = [('program', '0001_initial'), ('program', '0002_host_is_always_visible'), ('program', '0003_host_is_active'), ('program', '0004_show_is_active'), ('program', '0005_programslot_is_active'), ('program', '0006_note_remove_cba_entry_id'), ('program', '0007_show_remove_cba_series_id'), ('program', '0008_show_remove_automation_id'), ('program', '0009_host_remove_is_active'), ('program', '0010_show_remove_is_active'), ('program', '0011_programslot_remove_is_active'), ('program', '0012_auto_20180104_0005'), ('program', '0013_auto_20180124_1748'), ('program', '0014_auto_20180216_2000'), ('program', '0015_auto_20180218_1111'), ('program', '0016_auto_20180222_1253'), ('program', '0017_auto_20180314_1409'), ('program', '0018_auto_20190810_1146'), ('program', '0019_auto_20190810_1340'), ('program', '0020_auto_20190810_1341'), ('program', '0021_show_is_active'), ('program', '0022_show_is_public')]
+
+    initial = True
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Host',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('name', models.CharField(max_length=128, verbose_name='Name')),
+                ('email', models.EmailField(blank=True, max_length=254, verbose_name='E-Mail')),
+                ('website', models.URLField(blank=True, help_text='URL to your personal website.', verbose_name='Website')),
+                ('biography', tinymce.models.HTMLField(blank=True, help_text='Describe yourself and your fields of interest in a few sentences.', null=True, verbose_name='Biography')),
+                ('cba_url', models.URLField(blank=True, help_text='URL to your CBA profile.', verbose_name='CBA URL')),
+                ('dorftv_url', models.URLField(blank=True, help_text='URL to your dorfTV channel.', verbose_name='DorfTV URL')),
+                ('facebook_url', models.URLField(blank=True, help_text='URL to your Facebook profile.', verbose_name='Facebook URL')),
+                ('googleplus_url', models.URLField(blank=True, help_text='URL to your Google+ profile.', verbose_name='Google+ URL')),
+                ('height', models.PositiveIntegerField(blank=True, editable=False, null=True, verbose_name='Image Height')),
+                ('image', versatileimagefield.fields.VersatileImageField(blank=True, height_field='height', help_text="Upload a picture of yourself. Images are automatically cropped around the 'Primary Point of Interest'. Click in the image to change it and press Save.", null=True, upload_to='host_images', verbose_name='Profile picture', width_field='width')),
+                ('linkedin_url', models.URLField(blank=True, help_text='URL to your LinkedIn profile.', verbose_name='LinkedIn URL')),
+                ('ppoi', versatileimagefield.fields.PPOIField(default='0.5x0.5', editable=False, max_length=20, verbose_name='Image PPOI')),
+                ('twitter_url', models.URLField(blank=True, help_text='URL to your Twitter profile.', verbose_name='Twitter URL')),
+                ('width', models.PositiveIntegerField(blank=True, editable=False, null=True, verbose_name='Image Width')),
+                ('youtube_url', models.URLField(blank=True, help_text='URL to your Youtube channel.', verbose_name='Youtube URL')),
+                ('is_active', models.BooleanField(default=True, verbose_name='Is active?')),
+            ],
+            options={
+                'ordering': ('name',),
+                'verbose_name': 'Host',
+                'verbose_name_plural': 'Hosts',
+            },
+        ),
+        migrations.CreateModel(
+            name='MusicFocus',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('focus', models.CharField(max_length=32, verbose_name='Focus')),
+                ('abbrev', models.CharField(max_length=4, unique=True, verbose_name='Abbreviation')),
+                ('slug', models.SlugField(max_length=32, unique=True, verbose_name='Slug')),
+                ('button', models.ImageField(blank=True, null=True, upload_to='buttons', verbose_name='Button image')),
+                ('button_hover', models.ImageField(blank=True, null=True, upload_to='buttons', verbose_name='Button image (hover)')),
+                ('big_button', models.ImageField(blank=True, null=True, upload_to='buttons', verbose_name='Big button image')),
+                ('is_active', models.BooleanField(default=True, verbose_name='Is active?')),
+            ],
+            options={
+                'ordering': ('focus',),
+                'verbose_name': 'Music focus',
+                'verbose_name_plural': 'Music focus',
+            },
+        ),
+        migrations.CreateModel(
+            name='RRule',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('name', models.CharField(max_length=32, unique=True, verbose_name='Name')),
+                ('freq', models.IntegerField(choices=[(1, 'Monthly'), (2, 'Weekly'), (3, 'Daily')], verbose_name='Frequency')),
+                ('interval', models.IntegerField(default=1, verbose_name='Interval')),
+                ('bysetpos', models.IntegerField(blank=True, choices=[(1, 'First'), (2, 'Second'), (3, 'Third'), (4, 'Fourth'), (5, 'Fifth'), (-1, 'Last')], null=True, verbose_name='Set position')),
+                ('count', models.IntegerField(blank=True, null=True, verbose_name='Count')),
+            ],
+            options={
+                'ordering': ('pk',),
+                'verbose_name': 'Recurrence rule',
+                'verbose_name_plural': 'Recurrence rules',
+            },
+        ),
+        migrations.CreateModel(
+            name='Show',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('name', models.CharField(help_text="The show's name. Avoid a subtitle.", max_length=255, verbose_name='Name')),
+                ('slug', models.CharField(help_text='A simple to read URL for your show', max_length=255, unique=True, verbose_name='Slug')),
+                ('image', versatileimagefield.fields.VersatileImageField(blank=True, height_field='height', help_text="Upload an image to your show. Images are automatically cropped around the 'Primary Point of Interest'. Click in the image to change it and press Save.", null=True, upload_to='show_images', verbose_name='Image', width_field='width')),
+                ('short_description', models.TextField(help_text='Describe your show in some sentences. Avoid technical data like airing times and contact information. They will be added automatically.', verbose_name='Short description')),
+                ('description', tinymce.models.HTMLField(blank=True, help_text='Describe your show in detail.', null=True, verbose_name='Description')),
+                ('email', models.EmailField(blank=True, help_text='The main contact email address for your show.', max_length=254, null=True, verbose_name='E-Mail')),
+                ('website', models.URLField(blank=True, help_text='Is there a website to your show? Type in its URL.', null=True, verbose_name='Website')),
+                ('created', models.DateTimeField(auto_now_add=True)),
+                ('last_updated', models.DateTimeField(auto_now=True)),
+                ('hosts', models.ManyToManyField(blank=True, related_name='shows', to='program.Host', verbose_name='Hosts')),
+                ('musicfocus', models.ManyToManyField(blank=True, related_name='shows', to='program.MusicFocus', verbose_name='Music focus')),
+                ('owners', models.ManyToManyField(blank=True, related_name='shows', to=settings.AUTH_USER_MODEL, verbose_name='Owners')),
+                ('predecessor', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='successors', to='program.Show', verbose_name='Predecessor')),
+                ('cba_series_id', models.IntegerField(blank=True, help_text='Link your show to a CBA series by giving its ID. This will enable CBA upload and will automatically link your show to your CBA archive. Find out your ID under https://cba.fro.at/series', null=True, verbose_name='CBA Series ID')),
+                ('fallback_id', models.IntegerField(blank=True, null=True, verbose_name='Fallback ID')),
+                ('height', models.PositiveIntegerField(blank=True, editable=False, null=True, verbose_name='Image Height')),
+                ('logo', models.ImageField(blank=True, null=True, upload_to='show_images', verbose_name='Logo')),
+                ('ppoi', versatileimagefield.fields.PPOIField(default='0.5x0.5', editable=False, max_length=20, verbose_name='Image PPOI')),
+                ('width', models.PositiveIntegerField(blank=True, editable=False, null=True, verbose_name='Image Width')),
+            ],
+            options={
+                'ordering': ('slug',),
+                'verbose_name': 'Show',
+                'verbose_name_plural': 'Shows',
+            },
+        ),
+        migrations.CreateModel(
+            name='TimeSlot',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('start', models.DateTimeField(verbose_name='Start time')),
+                ('end', models.DateTimeField(verbose_name='End time')),
+                ('show', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='timeslots', to='program.Show')),
+                ('is_repetition', models.BooleanField(default=False, verbose_name='REP')),
+                ('memo', models.TextField(blank=True, verbose_name='Memo')),
+                ('playlist_id', models.IntegerField(null=True, verbose_name='Playlist ID')),
+            ],
+            options={
+                'ordering': ('start', 'end'),
+                'verbose_name': 'Time slot',
+                'verbose_name_plural': 'Time slots',
+            },
+        ),
+        migrations.CreateModel(
+            name='Category',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('category', models.CharField(max_length=32, verbose_name='Category')),
+                ('abbrev', models.CharField(max_length=4, unique=True, verbose_name='Abbreviation')),
+                ('slug', models.SlugField(max_length=32, unique=True, verbose_name='Slug')),
+                ('color', models.TextField(blank=True, max_length=7, verbose_name='Color')),
+                ('description', models.TextField(blank=True, verbose_name='Description')),
+                ('button', models.ImageField(blank=True, null=True, upload_to='buttons', verbose_name='Button image')),
+                ('button_hover', models.ImageField(blank=True, null=True, upload_to='buttons', verbose_name='Button image (hover)')),
+                ('big_button', models.ImageField(blank=True, null=True, upload_to='buttons', verbose_name='Big button image')),
+                ('is_active', models.BooleanField(default=True, verbose_name='Is active?')),
+            ],
+            options={
+                'verbose_name': 'Category',
+                'verbose_name_plural': 'Categories',
+                'ordering': ('category',),
+            },
+        ),
+        migrations.CreateModel(
+            name='Language',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('name', models.CharField(max_length=32, verbose_name='Language')),
+                ('is_active', models.BooleanField(default=True, verbose_name='Is active?')),
+            ],
+            options={
+                'verbose_name': 'Language',
+                'verbose_name_plural': 'Languages',
+                'ordering': ('language',),
+            },
+        ),
+        migrations.CreateModel(
+            name='Schedule',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('byweekday', models.IntegerField(choices=[(0, 'Monday'), (1, 'Tuesday'), (2, 'Wednesday'), (3, 'Thursday'), (4, 'Friday'), (5, 'Saturday'), (6, 'Sunday')], verbose_name='Weekday')),
+                ('dstart', models.DateField(verbose_name='First date')),
+                ('tstart', models.TimeField(verbose_name='Start time')),
+                ('tend', models.TimeField(verbose_name='End time')),
+                ('until', models.DateField(verbose_name='Last date')),
+                ('is_repetition', models.BooleanField(default=False, verbose_name='Is repetition')),
+                ('fallback_id', models.IntegerField(blank=True, null=True, verbose_name='Fallback ID')),
+                ('automation_id', models.IntegerField(blank=True, null=True, verbose_name='Automation ID')),
+                ('created', models.DateTimeField(auto_now_add=True, null=True)),
+                ('last_updated', models.DateTimeField(auto_now=True, null=True)),
+                ('rrule', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='schedules', to='program.RRule', verbose_name='Recurrence rule')),
+                ('show', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='schedules', to='program.Show', verbose_name='Show')),
+                ('add_business_days_only', models.BooleanField(default=False, verbose_name='Only add business days?')),
+                ('add_days_no', models.IntegerField(blank=True, null=True, verbose_name='Add days')),
+            ],
+            options={
+                'verbose_name': 'Schedule',
+                'verbose_name_plural': 'Schedules',
+                'ordering': ('dstart', 'tstart'),
+            },
+        ),
+        migrations.CreateModel(
+            name='Topic',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('topic', models.CharField(max_length=32, verbose_name='Topic')),
+                ('abbrev', models.CharField(max_length=4, unique=True, verbose_name='Abbreviation')),
+                ('slug', models.SlugField(max_length=32, unique=True, verbose_name='Slug')),
+                ('button', models.ImageField(blank=True, null=True, upload_to='buttons', verbose_name='Button image')),
+                ('button_hover', models.ImageField(blank=True, null=True, upload_to='buttons', verbose_name='Button image (hover)')),
+                ('big_button', models.ImageField(blank=True, null=True, upload_to='buttons', verbose_name='Big button image')),
+                ('is_active', models.BooleanField(default=True, verbose_name='Is active?')),
+            ],
+            options={
+                'verbose_name': 'Topic',
+                'verbose_name_plural': 'Topics',
+                'ordering': ('topic',),
+            },
+        ),
+        migrations.CreateModel(
+            name='Type',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('type', models.CharField(max_length=32, verbose_name='Type')),
+                ('slug', models.SlugField(max_length=32, unique=True, verbose_name='Slug')),
+                ('color', models.CharField(default='#ffffff', max_length=7, verbose_name='Color')),
+                ('text_color', models.CharField(default='#000000', max_length=7, verbose_name='Text color')),
+                ('is_active', models.BooleanField(default=True, verbose_name='Is active?')),
+            ],
+            options={
+                'verbose_name': 'Type',
+                'verbose_name_plural': 'Types',
+                'ordering': ('type',),
+            },
+        ),
+        migrations.CreateModel(
+            name='Note',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('title', models.CharField(help_text="Give your note a good headline. What will your upcoming show be about? Try to arouse interest to listen to it!<br>Avoid technical data like the show's name, its airing times or its episode number. These data are added automatically.", max_length=128, verbose_name='Title')),
+                ('content', tinymce.models.HTMLField(help_text='Describe your upcoming show in detail.', verbose_name='Content')),
+                ('status', models.IntegerField(choices=[(0, 'Cancellation'), (1, 'Recommendation'), (2, 'Repetition')], default=1, verbose_name='Status')),
+                ('start', models.DateTimeField(editable=False)),
+                ('created', models.DateTimeField(auto_now_add=True)),
+                ('last_updated', models.DateTimeField(auto_now=True)),
+                ('show', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notes', to='program.Show')),
+                ('timeslot', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='program.TimeSlot', verbose_name='Time slot')),
+                ('audio_url', models.TextField(blank=True, editable=False, verbose_name='Direct URL to a linked audio file')),
+                ('cba_id', models.IntegerField(blank=True, help_text="Link the note to a certain CBA post by giving its ID. (E.g. if your post's CBA URL is https://cba.fro.at/1234, then your CBA ID is 1234)", null=True, verbose_name='CBA ID')),
+                ('height', models.PositiveIntegerField(blank=True, editable=False, null=True, verbose_name='Image Height')),
+                ('host', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='hosts', to='program.Host')),
+                ('image', versatileimagefield.fields.VersatileImageField(blank=True, height_field='height', help_text="Upload an image to your note. Images are automatically cropped around the 'Primary Point of Interest'. Click in the image to change it and press Save.", null=True, upload_to='note_images', verbose_name='Featured image', width_field='width')),
+                ('ppoi', versatileimagefield.fields.PPOIField(default='0.5x0.5', editable=False, max_length=20, verbose_name='Image PPOI')),
+                ('slug', models.SlugField(default=1, help_text='A simple to read URL for your show.', max_length=32, unique=True, verbose_name='Slug')),
+                ('summary', models.TextField(blank=True, help_text='Describe your upcoming show in some sentences. Avoid technical data like airing times and contact information. They will be added automatically.', verbose_name='Summary')),
+                ('user', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='users', to=settings.AUTH_USER_MODEL)),
+                ('width', models.PositiveIntegerField(blank=True, editable=False, null=True, verbose_name='Image Width')),
+            ],
+            options={
+                'ordering': ('timeslot',),
+                'verbose_name': 'Note',
+                'verbose_name_plural': 'Notes',
+            },
+        ),
+        migrations.AddField(
+            model_name='show',
+            name='category',
+            field=models.ManyToManyField(blank=True, related_name='shows', to='program.Category', verbose_name='Category'),
+        ),
+        migrations.AddField(
+            model_name='show',
+            name='language',
+            field=models.ManyToManyField(blank=True, related_name='language', to='program.Language', verbose_name='Language'),
+        ),
+        migrations.AddField(
+            model_name='show',
+            name='topic',
+            field=models.ManyToManyField(blank=True, related_name='shows', to='program.Topic', verbose_name='Topic'),
+        ),
+        migrations.AddField(
+            model_name='show',
+            name='type',
+            field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='shows', to='program.Type', verbose_name='Type'),
+            preserve_default=False,
+        ),
+        migrations.AddField(
+            model_name='timeslot',
+            name='schedule',
+            field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='timeslots', to='program.Schedule', verbose_name='Schedule'),
+            preserve_default=False,
+        ),
+        migrations.AlterField(
+            model_name='timeslot',
+            name='is_repetition',
+            field=models.BooleanField(default=False, verbose_name='(REP)'),
+        ),
+        migrations.CreateModel(
+            name='FundingCategory',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('fundingcategory', models.CharField(max_length=32, verbose_name='Funding Category')),
+                ('abbrev', models.CharField(max_length=4, unique=True, verbose_name='Abbreviation')),
+                ('slug', models.SlugField(max_length=32, unique=True, verbose_name='Slug')),
+                ('is_active', models.BooleanField(default=True, verbose_name='Is active?')),
+            ],
+            options={
+                'verbose_name': 'Funding Category',
+                'verbose_name_plural': 'Funding Categories',
+                'ordering': ('fundingcategory',),
+            },
+        ),
+        migrations.AddField(
+            model_name='timeslot',
+            name='note_id',
+            field=models.IntegerField(editable=False, null=True, verbose_name='Note ID'),
+        ),
+        migrations.AlterField(
+            model_name='timeslot',
+            name='is_repetition',
+            field=models.BooleanField(default=False, verbose_name='Is repetition?'),
+        ),
+        migrations.AlterField(
+            model_name='show',
+            name='cba_series_id',
+            field=models.IntegerField(blank=True, help_text="Link your show to a CBA series by giving its ID. This will enable CBA upload and will automatically link your show to your CBA archive. Find out your show's ID under https://cba.fro.at/series", null=True, verbose_name='CBA Series ID'),
+        ),
+        migrations.AlterField(
+            model_name='show',
+            name='fallback_id',
+            field=models.IntegerField(blank=True, help_text='If a timeslot of your show is empty, this playlist will be aired as a backup.', null=True, verbose_name='Fallback ID'),
+        ),
+        migrations.AlterField(
+            model_name='show',
+            name='logo',
+            field=models.ImageField(blank=True, help_text='Upload a logo of your show.', null=True, upload_to='show_images', verbose_name='Logo'),
+        ),
+        migrations.AlterField(
+            model_name='show',
+            name='short_description',
+            field=models.TextField(help_text='Describe your show for your listeners in some sentences. Avoid technical data like airing times and contact information. They will be added automatically.', verbose_name='Short description'),
+        ),
+        migrations.AddField(
+            model_name='show',
+            name='fundingcategory',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='shows', to='program.FundingCategory', verbose_name='Funding Category'),
+        ),
+        migrations.AddField(
+            model_name='show',
+            name='is_active',
+            field=models.BooleanField(default=True, verbose_name='Is active?'),
+        ),
+        migrations.AddField(
+            model_name='show',
+            name='is_public',
+            field=models.BooleanField(default=False, help_text='Files and Playlists of Public Shows can only be changed by owners but may be used by everyone.', verbose_name='Is Public?'),
+        ),
+    ]