diff --git a/aleksis/apps/alsijil/migrations/0019_add_documentation_and_participation.py b/aleksis/apps/alsijil/migrations/0020_add_documentation_and_participation.py
similarity index 91%
rename from aleksis/apps/alsijil/migrations/0019_add_documentation_and_participation.py
rename to aleksis/apps/alsijil/migrations/0020_add_documentation_and_participation.py
index 9a23bd3f4016d57293367ddd878f7fb184f4659e..4d910b912e038f5e65f2ba9e5b0947e52297f199 100644
--- a/aleksis/apps/alsijil/migrations/0019_add_documentation_and_participation.py
+++ b/aleksis/apps/alsijil/migrations/0020_add_documentation_and_participation.py
@@ -9,11 +9,10 @@ import django.db.models.deletion
 class Migration(migrations.Migration):
 
     dependencies = [
-        ("sites", "0002_alter_domain_unique"),
-        ("chronos", "0015_add_managed_by_app_label"),
+        ("chronos", "0016_lessonevent"),
         ("core", "0052_site_related_name"),
         ("cursus", "0001_initial"),
-        ("alsijil", "0018_add_managed_by_app_label"),
+        ("alsijil", "0019_drop_sites"),
     ]
 
     operations = [
@@ -120,16 +119,6 @@ class Migration(migrations.Migration):
                         to="core.person",
                     ),
                 ),
-                (
-                    "site",
-                    models.ForeignKey(
-                        default=1,
-                        editable=False,
-                        on_delete=django.db.models.deletion.CASCADE,
-                        related_name="+",
-                        to="sites.site",
-                    ),
-                ),
             ],
             options={
                 "verbose_name": "Participation note",
diff --git a/aleksis/apps/alsijil/migrations/0021_participationstatus.py b/aleksis/apps/alsijil/migrations/0021_participationstatus.py
new file mode 100644
index 0000000000000000000000000000000000000000..5f3a7225f0301609a424aed6354bde13f97b086a
--- /dev/null
+++ b/aleksis/apps/alsijil/migrations/0021_participationstatus.py
@@ -0,0 +1,113 @@
+# Generated by Django 4.2.9 on 2024-01-11 20:43
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('cursus', '0001_initial'),
+        ('core', '0052_site_related_name'),
+        ('chronos', '0016_lessonevent'),
+        ('kolego', '0003_refactor_absence'),
+        ('alsijil', '0020_add_documentation_and_participation'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='NewPersonalNote',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('managed_by_app_label', models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance')),
+                ('extended_data', models.JSONField(default=dict, editable=False)),
+                ('note', models.TextField(blank=True, verbose_name='Note')),
+            ],
+            options={
+                'verbose_name': 'Personal Note',
+                'verbose_name_plural': 'Personal Notes',
+            },
+        ),
+        migrations.CreateModel(
+            name='ParticipationStatus',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('managed_by_app_label', models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance')),
+                ('extended_data', models.JSONField(default=dict, editable=False)),
+                ('absent', models.BooleanField(verbose_name='Absent')),
+                ('absence_reason', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='kolego.absencereason', verbose_name='Absence Reason')),
+                ('base_absence', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='absences', to='kolego.absence', verbose_name='Base Absence')),
+            ],
+            options={
+                'verbose_name': 'Participation Status',
+                'verbose_name_plural': 'Participation Status',
+                'ordering': ['documentation', 'person__last_name', 'person__first_name'],
+            },
+        ),
+        migrations.AlterField(
+            model_name='documentation',
+            name='course',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='documentations', to='cursus.course', verbose_name='Course'),
+        ),
+        migrations.AlterField(
+            model_name='documentation',
+            name='group_note',
+            field=models.CharField(blank=True, max_length=255, verbose_name='Group Note'),
+        ),
+        migrations.AlterField(
+            model_name='documentation',
+            name='lesson_event',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='documentation', to='chronos.lessonevent', verbose_name='Lesson Event'),
+        ),
+        migrations.AlterField(
+            model_name='documentation',
+            name='subject',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='cursus.subject', verbose_name='Subject'),
+        ),
+        migrations.AlterField(
+            model_name='documentation',
+            name='topic',
+            field=models.CharField(blank=True, max_length=255, verbose_name='Lesson Topic'),
+        ),
+        migrations.DeleteModel(
+            name='Participation',
+        ),
+        migrations.AddField(
+            model_name='participationstatus',
+            name='documentation',
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='participations', to='alsijil.documentation', verbose_name='Documentation'),
+        ),
+        migrations.AddField(
+            model_name='participationstatus',
+            name='groups_of_person',
+            field=models.ManyToManyField(related_name='+', to='core.group', verbose_name='Groups of Person'),
+        ),
+        migrations.AddField(
+            model_name='participationstatus',
+            name='person',
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='participations', to='core.person', verbose_name='Person'),
+        ),
+        migrations.AddField(
+            model_name='newpersonalnote',
+            name='documentation',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='personal_notes', to='alsijil.documentation', verbose_name='Documentation'),
+        ),
+        migrations.AddField(
+            model_name='newpersonalnote',
+            name='extra_mark',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='alsijil.extramark', verbose_name='Extra Mark'),
+        ),
+        migrations.AddField(
+            model_name='newpersonalnote',
+            name='person',
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='new_personal_notes', to='core.person', verbose_name='Person'),
+        ),
+        migrations.AddConstraint(
+            model_name='participationstatus',
+            constraint=models.UniqueConstraint(fields=('documentation', 'person'), name='unique_participation_status_per_documentation'),
+        ),
+        migrations.AddConstraint(
+            model_name='newpersonalnote',
+            constraint=models.CheckConstraint(check=models.Q(models.Q(('note', ''), _negated=True), ('extra_mark__isnull', False), _connector='OR'), name='unique_absence_per_documentation'),
+        ),
+    ]
diff --git a/aleksis/apps/alsijil/models.py b/aleksis/apps/alsijil/models.py
index 3579a6db4205e2cb13563e5989b976832e83f046..e86bbed4c4d42a6f80de114f7815a79e52af6c20 100644
--- a/aleksis/apps/alsijil/models.py
+++ b/aleksis/apps/alsijil/models.py
@@ -454,7 +454,7 @@ class Documentation(CalendarEvent):
 
     course = models.ForeignKey(
         Course,
-        models.CASCADE,
+        models.PROTECT,
         related_name="documentations",
         blank=True,
         null=True,
@@ -463,7 +463,7 @@ class Documentation(CalendarEvent):
 
     lesson_event = models.ForeignKey(
         LessonEvent,
-        models.CASCADE,
+        models.PROTECT,
         related_name="documentation",
         blank=True,
         null=True,
@@ -471,7 +471,7 @@ class Documentation(CalendarEvent):
     )
 
     subject = models.ForeignKey(
-        Subject, models.CASCADE, related_name="+", blank=True, null=True, verbose_name=_("Subject")
+        Subject, models.PROTECT, related_name="+", blank=True, null=True, verbose_name=_("Subject")
     )
 
     topic = models.CharField(verbose_name=_("Lesson Topic"), max_length=255, blank=True)
@@ -496,8 +496,8 @@ class Documentation(CalendarEvent):
             return self.course.groups.all()
 
     def __str__(self) -> str:
-        start_datetime = CalendarEvent.value_start_datetime(self, None)
-        end_datetime = CalendarEvent.value_end_datetime(self, None)
+        start_datetime = CalendarEvent.value_start_datetime(self)
+        end_datetime = CalendarEvent.value_end_datetime(self)
         return (
             f"{format_m2m(self.get_groups())} {self.get_subject()}"
             + f" {start_datetime} - {end_datetime}"
@@ -514,10 +514,10 @@ class Documentation(CalendarEvent):
         ]
 
 
-class Participation(ExtensibleModel):
-    """A participation record about a single person.
+class ParticipationStatus(ExtensibleModel):
+    """A participation or absence record about a single person.
 
-    Used in the class register to note participation of a student
+    Used in the class register to note participation or absence of a student
     in a documented unit (e.g. a single lesson event or a custom time frame; see Documentation).
     """
 
@@ -537,61 +537,22 @@ class Participation(ExtensibleModel):
         verbose_name=_("Documentation"),
     )
 
-    def __str__(self) -> str:
-        return f"{self.documentation}, {self.person}"
-
-    class Meta:
-        verbose_name = _("Participation note")
-        verbose_name_plural = _("Participation notes")
-        ordering = [
-            "documentation",
-            "person__last_name",
-            "person__first_name",
-        ]
-        constraints = [
-            models.UniqueConstraint(
-                fields=("documentation", "person"),
-                name="unique_participation_per_documentation",
-            ),
-        ]
-
-
-class Absence(ExtensibleModel):
-    """An absence record about a single person.
-
-    Used in the class register to note absence of a student
-    in a documented unit (e.g. a single lesson event or a custom time frame; see Documentation).
-    """
-
-    # FIXME: DataChecks
-
-    reason = models.ForeignKey(
-        AbsenceReason, verbose_name=_("Absence Reason"), on_delete=models.CASCADE
-    )
-
-    person = models.ForeignKey(
-        "core.Person", models.CASCADE, related_name="lesson_absences", verbose_name=_("Person")
-    )
-    groups_of_person = models.ManyToManyField(
-        "core.Group", related_name="+", verbose_name=_("Groups of Person")
-    )
-
-    documentation = models.ForeignKey(
-        Documentation, models.CASCADE, related_name="absences", verbose_name=_("Documentation")
+    # Absence part
+    absent = models.BooleanField(verbose_name=_("Absent"))
+    absence_reason = models.ForeignKey(
+        AbsenceReason, verbose_name=_("Absence Reason"), on_delete=models.PROTECT
     )
 
-    excused = models.BooleanField(default=False, verbose_name=_("Excused"))
-
     base_absence = models.ForeignKey(
-        KolegoAbsence, models.SET_NULL, related_name="absences", verbose_name=_("Base Absence")
+        KolegoAbsence, models.SET_NULL, blank=True, null=True, related_name="absences", verbose_name=_("Base Absence")
     )
 
     def __str__(self) -> str:
         return f"{self.documentation}, {self.person}"
 
     class Meta:
-        verbose_name = _("Absence note")
-        verbose_name_plural = _("Absence notes")
+        verbose_name = _("Participation Status")
+        verbose_name_plural = _("Participation Status")
         ordering = [
             "documentation",
             "person__last_name",
@@ -600,11 +561,13 @@ class Absence(ExtensibleModel):
         constraints = [
             models.UniqueConstraint(
                 fields=("documentation", "person"),
-                name="unique_absence_per_documentation",
+                name="unique_participation_status_per_documentation",
             ),
         ]
 
 
+
+
 class NewPersonalNote(ExtensibleModel):
     person = models.ForeignKey(
         "core.Person", models.CASCADE, related_name="new_personal_notes", verbose_name=_("Person")
@@ -621,7 +584,7 @@ class NewPersonalNote(ExtensibleModel):
 
     note = models.TextField(blank=True, verbose_name=_("Note"))
     extra_mark = models.ForeignKey(
-        ExtraMark, on_delete=models.CASCADE, blank=True, null=True, verbose_name=_("Extra Mark")
+        ExtraMark, on_delete=models.PROTECT, blank=True, null=True, verbose_name=_("Extra Mark")
     )
 
     def __str__(self) -> str:
diff --git a/pyproject.toml b/pyproject.toml
index c19624053cb6d7c1c5779163f9cb66bda9bf9961..0e35ee18b56fae8ed96d9546021da00c5a4f8e74 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -52,7 +52,7 @@ python = "^3.10"
 aleksis-core = "^4.0.0.dev2"
 aleksis-app-chronos = "^4.0.0.dev0"
 aleksis-app-stoelindeling = { version = "^3.0.dev1", optional = true }
-
+aleksis-app-kolego = { path = "../../onboarding/AlekSIS-App-Kolego", develop = true }
 [tool.poetry.extras]
 seatingplans = ["aleksis-app-stoelindeling"]