diff --git a/AKModel/models.py b/AKModel/models.py
index ac454086a8592a5dfb8882049c56522f7a983bc6..5a257cd56d25ceb187f7d4337395d87ae6638ae5 100644
--- a/AKModel/models.py
+++ b/AKModel/models.py
@@ -346,6 +346,9 @@ class AKSlot(models.Model):
         """
         return (timezone.now() - self.updated).total_seconds()
 
+    def overlaps(self, other: "AKSlot"):
+        return self.start <= other.end  <= self.end or self.start <= other.start <= self.end
+
 
 class AKOrgaMessage(models.Model):
     ak = models.ForeignKey(to=AK, on_delete=models.CASCADE, verbose_name=_('AK'), help_text=_('AK this message belongs to'))
@@ -401,8 +404,8 @@ class ConstraintViolation(models.Model):
     timestamp = models.DateTimeField(auto_now_add=True, verbose_name=_('Timestamp'), help_text=_('Time of creation'))
     manually_resolved = models.BooleanField(verbose_name=_('Manually Resolved'), default=False, help_text=_('Mark this violation manually as resolved'))
 
-    fields = ['ak_owner', 'room', 'requirement', 'category']
-    fields_mm = ['aks', 'ak_slots']
+    FIELDS = ['ak_owner', 'room', 'requirement', 'category']
+    FIELDS_MM = ['_aks', '_ak_slots']
 
     def get_details(self):
         """
@@ -412,15 +415,53 @@ class ConstraintViolation(models.Model):
         """
         output = []
         # Stringify all ManyToMany fields
-        for field_mm in self.fields_mm:
-            output.append(f"{field_mm}: {', '.join(str(a) for a in getattr(self, field_mm).all())}")
+        for field_mm in self.FIELDS_MM:
+            output.append(f"{field_mm[1:]}: {', '.join(str(a) for a in getattr(self, field_mm))}")
         # Stringify all other fields
-        for field in self.fields:
+        for field in self.FIELDS:
             a = getattr(self, field, None)
             if a is not None:
                 output.append(f"{field}: {a}")
         return ", ".join(output)
     get_details.short_description = _('Details')
 
+    # TODO Automatically save this
+    aks_tmp = set()
+    @property
+    def _aks(self):
+        """
+        Get all AKs belonging to this constraint violation
+
+        The distinction between real and tmp relationships is needed since many to many
+        relations only work for objects already persisted in the database
+
+        :return: set of all AKs belonging to this constraint violation
+        :rtype: set(AK)
+        """
+        if self.pk and self.pk > 0:
+            return set(self.aks.all())
+        return self.aks_tmp
+
+    # TODO Automatically save this
+    ak_slots_tmp = set()
+    @property
+    def _ak_slots(self):
+        """
+        Get all AK Slots belonging to this constraint violation
+
+        The distinction between real and tmp relationships is needed since many to many
+        relations only work for objects already persisted in the database
+
+        :return: set of all AK Slots belonging to this constraint violation
+        :rtype: set(AKSlot)
+        """
+        if self.pk and self.pk > 0:
+            return set(self.ak_slots.all())
+        return self.ak_slots_tmp
+
     def __str__(self):
         return f"{self.get_level_display()}: {self.get_type_display()} [{self.get_details()}]"
+
+    def __eq__(self, other):
+        # TODO Check if FIELDS and FIELDS_MM are equal
+        return super().__eq__(other)
diff --git a/AKScheduling/models.py b/AKScheduling/models.py
index 6b2021999398416a78191ac543b7e0e34d86bc2c..990bcd4a74b6efebdc865830abd5cafb8600ae21 100644
--- a/AKScheduling/models.py
+++ b/AKScheduling/models.py
@@ -1 +1,80 @@
-# Create your models here.
+from django.db.models.signals import post_save
+from django.dispatch import receiver
+
+from AKModel.availability.models import Availability
+from AKModel.models import AK, AKSlot, Room, Event, AKOwner, ConstraintViolation
+
+
+@receiver(post_save, sender=AK)
+def ak_changed_handler(sender, instance: AK, **kwargs):
+    # Changes might affect: Owner(s), Requirements, Conflicts, Prerequisites, Category, Interest
+    print(f"{instance} changed")
+
+    event = instance.event
+
+    # Owner might have changed: Might affect multiple AKs by the same owner at the same time
+    conflicts = []
+    type = ConstraintViolation.ViolationType.OWNER_TWO_SLOTS
+    # For all owners...
+    for owner in instance.owners.all():
+        # ...find overlapping AKs...
+        slots_by_owner : [AKSlot] = []
+        slots_by_owner_this_ak : [AKSlot] = []
+        aks_by_owner = owner.ak_set.all()
+        for ak in aks_by_owner:
+            if ak != instance:
+                slots_by_owner.extend(ak.akslot_set.filter(start__isnull=False))
+            else:
+                # ToDo Fill this outside of loop?
+                slots_by_owner_this_ak.extend(ak.akslot_set.filter(start__isnull=False))
+        for slot in slots_by_owner_this_ak:
+            for other_slot in slots_by_owner:
+                if slot.overlaps(other_slot):
+                    # TODO Create ConstraintViolation here
+                    c = ConstraintViolation(
+                        type=type,
+                        level=ConstraintViolation.ViolationLevel.VIOLATION,
+                        event=event,
+                        ak_owner=owner
+                    )
+                    c.aks_tmp.add(instance)
+                    c.aks_tmp.add(other_slot.ak)
+                    c.ak_slots_tmp.add(slot)
+                    c.ak_slots_tmp.add(other_slot)
+                    conflicts.append(c)
+        print(f"{owner} has the following conflicts: {conflicts}")
+    # ... and compare to/update list of existing violations of this type:
+    current_violations = instance.constraintviolation_set.filter(type=type)
+    for conflict in conflicts:
+        pass
+        # TODO Remove from list of current_violations if an equal new one is found
+        # TODO Otherwise, store this conflict in db
+    # TODO Remove all violations still in current_violations
+
+
+@receiver(post_save, sender=AKSlot)
+def akslot_changed_handler(sender, instance, **kwargs):
+    # Changes might affect: Duplicate parallel, Two in room
+    print(f"{sender} changed")
+    # TODO Replace with real handling
+
+
+@receiver(post_save, sender=Room)
+def room_changed_handler(sender, **kwargs):
+    # Changes might affect: Room size, Requirement
+    print(f"{sender} changed")
+    # TODO Replace with real handling
+
+
+@receiver(post_save, sender=Availability)
+def availability_changed_handler(sender, **kwargs):
+    # Changes might affect: category availability, AK availability, Room availability
+    print(f"{sender} changed")
+    # TODO Replace with real handling
+
+
+@receiver(post_save, sender=Event)
+def room_changed_handler(sender, **kwargs):
+    # Changes might affect: Reso-Deadline
+    print(f"{sender} changed")
+    # TODO Replace with real handling