diff --git a/aleksis/apps/chronos/frontend/components/AmendLessonOverview.vue b/aleksis/apps/chronos/frontend/components/AmendLessonOverview.vue
new file mode 100644
index 0000000000000000000000000000000000000000..15b32e035f04e5eb78bdd0877fb646636ca9aedc
--- /dev/null
+++ b/aleksis/apps/chronos/frontend/components/AmendLessonOverview.vue
@@ -0,0 +1,153 @@
+<script setup>
+import AmendedLessonCard from "./AmendedLessonCard.vue";
+import CRUDIterator from "aleksis.core/components/generic/CRUDIterator.vue";
+import DateField from "aleksis.core/components/generic/forms/DateField.vue";
+import SubjectChip from "aleksis.apps.cursus/components/SubjectChip.vue";
+
+import { DateTime } from "luxon";
+
+import { amendedLessonsFromAbsences, batchPatchAmendLessons, gqlGroups } from "./amendLesson.graphql";
+</script>
+
+<template>
+  <c-r-u-d-iterator
+    :gql-query="gqlQuery"
+    :gql-patch-mutation="gqlPatchMutation"
+    :get-patch-data="gqlGetPatchData"
+    :gql-filters="gqlFilters"
+    i18n-key="test"
+    :enable-search="false"
+    :enable-filter="true"
+    :enable-create="false"
+    :show-create="false"
+    :enable-delete="false"
+    :enable-edit="true"
+    :headers="headers"
+    :force-model-item-update="true"
+    @lastQuery="lastQuery = $event"
+  >
+    <template #default="{ items }">
+      <v-list-item v-for="day in groupAmendedLessonsByDay(items)" two-line>
+        <v-list-item-content>
+          <v-list-item-title>{{ $d(day[0], "short") }}</v-list-item-title>
+          <v-list>
+            <v-list-item v-for="amendedLesson in day.slice(1)">
+              <amended-lesson-card :amended-lesson="amendedLesson" :affected-query="lastQuery" :is-create="false" :gql-patch-mutation="batchPatchAmendLessons" />
+            </v-list-item>
+          </v-list>
+        </v-list-item-content>
+      </v-list-item>
+    </template>
+
+    <!--<template #groups="{ item }">-->
+    <!--  <lesson-related-object-chip-->
+    <!--    v-for="group in item.realAmends.groups"-->
+    <!--    :key="group.id"-->
+    <!--  >-->
+    <!--    {{ group.shortName }}-->
+    <!--  </lesson-related-object-chip-->
+    <!--  >-->
+    <!--</template>-->
+
+    <!--<template #teachers.field="{ attrs, on, item }">-->
+    <!--  <v-autocomplete-->
+    <!--    :disabled="item.cancelled"-->
+    <!--    multiple-->
+    <!--    :items="amendableTeachers"-->
+    <!--    item-text="fullName"-->
+    <!--    item-value="id"-->
+    <!--    v-bind="attrs"-->
+    <!--    v-on="on"-->
+    <!--    chips-->
+    <!--    deletable-chips-->
+    <!--  />-->
+    <!--</template>-->
+    
+    <template #filters="{ attrs, on }">
+      <date-field
+        v-bind="attrs('date_start')"
+        v-on="on('date_start')"
+        :label="$t('start')"
+      />
+
+      <date-field
+        v-bind="attrs('date_end')"
+        v-on="on('date_end')"
+        :label="$t('end')"
+      />
+
+      <v-autocomplete
+        v-bind="attrs('group_id')"
+        v-on="on('group_id')"
+        :label="$t('group')"
+        :items="groups"
+        item-text="shortName"
+        item-value="id"
+      />
+    </template>
+  </c-r-u-d-iterator>
+</template>
+
+<script>
+  export default {
+    props: {
+    },
+    data() {
+      return {
+        gqlQuery: amendedLessonsFromAbsences,
+        gqlPatchMutation: batchPatchAmendLessons,
+        gqlFilters: {
+          group_id: 2,
+        },
+        headers: [
+          {
+            text: "date & time start",
+            value: "datetimeStart",
+            disableEdit: true,
+          },
+          {
+            text: "date & time end",
+            value: "datetimeEnd",
+            disableEdit: true,
+          },
+          {
+            text: "subject",
+            value: "subject",
+            disableEdit: true,
+          },
+          {
+            text: "groups",
+            value: "groups",
+            disableEdit: true,
+          },
+          {
+            text: "teachers",
+            value: "teachers",
+            cols: 12,
+          }
+        ],
+        lastQuery: null,
+      };
+    },
+    methods: {
+      groupAmendedLessonsByDay(amendedLessons) {
+        const byDay = amendedLessons.reduce((byDay, amendedLesson) => {
+          const day = DateTime.fromISO(amendedLesson.datetimeStart).startOf("day");
+          byDay[day] ??= [day];
+          byDay[day].push(amendedLesson);
+          return byDay;
+        }, {});
+
+        return Object.keys(byDay)
+        .sort()
+        .map((key) => byDay[key]);
+      },
+      gqlGetPatchData(item) {
+        return { id: item.id, teachers: item.teachers }
+      },
+    },
+    apollo: {
+      groups: gqlGroups,
+    }
+  };    
+</script>
diff --git a/aleksis/apps/chronos/frontend/components/AmendedLessonCard.vue b/aleksis/apps/chronos/frontend/components/AmendedLessonCard.vue
new file mode 100644
index 0000000000000000000000000000000000000000..a29a183853f384cd9e3c02d61b542f5fa662f589
--- /dev/null
+++ b/aleksis/apps/chronos/frontend/components/AmendedLessonCard.vue
@@ -0,0 +1,106 @@
+<script setup>
+import DeleteButton from "aleksis.core/components/generic/buttons/DeleteButton.vue";
+import LessonInformation from "./LessonInformation.vue";
+import LessonRelatedObjectChip from "./LessonRelatedObjectChip.vue";
+
+import { gqlPersons } from "./amendLesson.graphql";
+
+import createOrPatchMixin from "aleksis.core/mixins/createOrPatchMixin.js";
+</script>
+
+<template>
+  <v-card class="my-2 full-width">
+    <!-- flex-md-row zeile ab medium -->
+    <!-- align-stretch - stretch full-width -->
+    <div class="full-width d-flex flex-md-row flex-column align-center justify-space-between">
+      <lesson-information
+        class="flex-grow-1"
+        :lesson="$attrs['amended-lesson']"
+      />
+      
+      <v-autocomplete
+        v-model="teachers"
+        multiple
+        chips
+        deletable-chips
+        :items="amendableTeachers"
+        item-text="fullName"
+        item-value="id"
+        class="flex-grow-1 flex-shrink-0 mx-2"
+        @input="save"
+      >
+        <template #prepend-inner>
+          <v-chip v-for="teacher in teachersWithStatus($attrs['amended-lesson']).filter((t) => t.status === 'removed')" class="text-decoration-line-through text--secondary mb-2">{{ teacher.fullName }}</v-chip>
+        </template>
+      </v-autocomplete>
+      
+      <delete-button class="flex-grow-1 mx-2" color="red white--text" @click="toggleCancel">{{ $attrs['amended-lesson'].cancelled ? "de-cancel" : "cancel" }}</delete-button>
+    </div>
+    <v-divider/>
+    <!--<v-card-actions>-->
+    <!--  <v-spacer/>-->
+    <!--  <cancel-button @click="$emit('close')" :disabled="loading" />-->
+    <!--  <save-button-->
+    <!--    @click="save"-->
+    <!--    :loading="loading"-->
+    <!--  />-->
+    <!--</v-card-actions>-->
+  </v-card>
+</template>
+
+<script>
+//import SaveButton from "aleksis.core/components/generic/buttons/SaveButton.vue";
+//import CancelButton from "aleksis.core/components/generic/buttons/CancelButton.vue";
+//import CancelButton from "aleksis.core/components/generic/buttons/CancelButton.vue";
+
+//import { createOrUpdateDocumentations } from "../coursebook.graphql";
+
+export default {
+  name: "AmendedLessonCard",
+  emits: ["open", "close"],
+  mixins: [createOrPatchMixin],
+  data() {
+    return {
+      loading: false,
+      teachers: [],
+    };
+  },
+  methods: {
+    teachersWithStatus(lesson) {
+      let oldIds = lesson.realAmends.teachers.map((teacher) => teacher.id);
+      let newIds = lesson.teachers.map((teacher) => teacher.id);
+      let teachersWithStatus = lesson.realAmends.teachers.concat(lesson.teachers).map((teacher) => {
+        let status = "regular";
+        if (newIds.includes(teacher.id) && !oldIds.includes(teacher.id)) {
+          status = "new";
+        } else if (
+          !newIds.includes(teacher.id) &&
+          oldIds.includes(teacher.id)
+        ) {
+          status = "removed";
+        }
+        return { ...teacher, status: status };
+      });
+      return teachersWithStatus;
+    },
+    save() {
+      this.createOrPatch([{
+        id: this.$attrs["amended-lesson"].id,
+        teachers: this.teachers,
+      }]);
+    },
+    toggleCancel() {
+      this.createOrPatch([{
+        id: this.$attrs["amended-lesson"].id,
+        cancelled: !this.$attrs["amended-lesson"].cancelled,
+      }]);
+    },
+  },
+  apollo: {
+    amendableTeachers: gqlPersons,
+  },
+  mounted() {
+    this.teachers = this.$attrs["amended-lesson"].teachers.map((teacher) => teacher.id);
+  },
+};
+</script>
diff --git a/aleksis/apps/chronos/frontend/components/LessonInformation.vue b/aleksis/apps/chronos/frontend/components/LessonInformation.vue
new file mode 100644
index 0000000000000000000000000000000000000000..a43ab8b9bd7fcc67203af6f2b9742b68e1545b31
--- /dev/null
+++ b/aleksis/apps/chronos/frontend/components/LessonInformation.vue
@@ -0,0 +1,52 @@
+<script setup>
+import CancelledCalendarStatusChip from "aleksis.core/components/calendar/CancelledCalendarStatusChip.vue";
+import SubjectChip from "aleksis.apps.cursus/components/SubjectChip.vue";
+
+import { DateTime } from "luxon";
+</script>
+
+<template>
+  <v-card-text>
+    <cancelled-calendar-status-chip
+      v-if="lesson.cancelled"
+      class="mr-2"
+    />
+    <div :class="{ 'text-decoration-line-through': lesson.cancelled, 'text--secondary': lesson.cancelled }">
+      {{ $d(toDateTime(lesson.datetimeStart), "shortTime") }} –
+      {{ $d(toDateTime(lesson.datetimeEnd), "shortTime") }}
+      {{ getCourse(lesson)?.name }}
+    </div>
+    <subject-chip
+      v-if="getSubject(lesson)"
+      :subject="getSubject(lesson)"
+    />
+  </v-card-text>
+</template>
+
+<script>
+export default {
+  name: "LessonInformation",
+  props: {
+    lesson: {
+      type: Object,
+      required: true,
+    },
+    cancelled: {
+      type: Boolean,
+      required: false,
+      default: false,
+    },
+  },
+  methods: {
+    toDateTime(dateString) {
+      return DateTime.fromISO(dateString);
+    },
+    getSubject(lesson) {
+      return lesson.subject ? lesson.subject : lesson.course?.subject ? lesson.course.subject : lesson.realAmends?.subject ? lesson.realAmends.subject : undefined;
+    },
+    getCourse(lesson) {
+      return lesson.course ? lesson.course : lesson.realAmends?.course ? lesson.realAmends.course : undefined;
+    },
+  },
+};
+</script>
diff --git a/aleksis/apps/chronos/frontend/components/amendLesson.graphql b/aleksis/apps/chronos/frontend/components/amendLesson.graphql
index a93e89186df05efdfa77473b7f1a1751eb614c24..1868fca441804614354dbd7e2996f8d3013a6816 100644
--- a/aleksis/apps/chronos/frontend/components/amendLesson.graphql
+++ b/aleksis/apps/chronos/frontend/components/amendLesson.graphql
@@ -19,6 +19,14 @@ query gqlRooms {
   }
 }
 
+query gqlGroups {
+  groups: groups {
+    id
+    name
+    shortName
+  }
+}
+
 mutation createAmendLesson($input: CreateLessonEventInput!) {
   createAmendLesson(input: $input) {
     lessonEvent {
@@ -68,8 +76,133 @@ mutation patchAmendLesson($input: PatchLessonEventInput!, $id: ID!) {
   }
 }
 
+mutation batchPatchAmendLessons($input: [BatchPatchLessonEventInput]!) {
+  batchPatchAmendLessons(input: $input) {
+    items: lessonEvents {
+      id
+      subject {
+        id
+        shortName
+        name
+        colourFg
+        colourBg
+      }
+      teachers {
+        id
+        shortName
+        fullName
+      }
+      groups {
+        id
+      }
+      rooms {
+        id
+      }
+      course {
+        id
+        subject {
+          id
+          shortName
+          name
+          colourFg
+          colourBg
+        }
+      }
+      realAmends {
+        id
+        teachers {
+          id
+          shortName
+          fullName
+        }
+        subject {
+          id
+          shortName
+          name
+          colourFg
+          colourBg
+        }
+        groups {
+          id
+          shortName
+        }
+        course {
+          id
+          name
+        }
+      }
+      datetimeStart
+      datetimeEnd
+      cancelled
+      comment
+    }
+  }
+}
+
 mutation deleteAmendLesson($id: ID!) {
   deleteAmendLesson(id: $id) {
     ok
   }
 }
+
+query amendedLessonsFromAbsences($filters: JSONString!) {
+  items: amendedLessonsFromAbsences(filters: $filters) {
+    id
+    subject {
+      id
+      shortName
+      name
+      colourFg
+      colourBg
+    }
+    teachers {
+      id
+      shortName
+      fullName
+    }
+    groups {
+      id
+    }
+    course {
+      id
+      subject {
+        id
+        shortName
+        name
+        colourFg
+        colourBg
+      }
+      name
+    }
+    rooms {
+      id
+    }
+    realAmends {
+      id
+      teachers {
+        id
+        shortName
+        fullName
+      }
+      subject {
+        id
+        shortName
+        name
+        colourFg
+        colourBg
+      }
+      groups {
+        id
+        shortName
+      }
+      course {
+        id
+        name
+      }
+    }
+    datetimeStart
+    datetimeEnd
+    cancelled
+    comment
+  }
+}
diff --git a/aleksis/apps/chronos/frontend/index.js b/aleksis/apps/chronos/frontend/index.js
index 30451f93c2f0dfcb769a4ab92385b50fe1bfe61c..494a0e90ee48dd92cb7747c9f304bb3460124228 100644
--- a/aleksis/apps/chronos/frontend/index.js
+++ b/aleksis/apps/chronos/frontend/index.js
@@ -1,5 +1,6 @@
 import { hasPersonValidator } from "aleksis.core/routeValidators";
 import Timetable from "./components/Timetable.vue";
+import AmendLessonOverview from "./components/AmendLessonOverview.vue"
 
 export default {
   meta: {
@@ -31,5 +32,15 @@ export default {
         permission: "chronos.view_timetable_overview_rule",
       },
     },
+    {
+      path: "amend_lesson_overview/",
+      component: AmendLessonOverview,
+      name: "chronos.amendLessonOverview",
+      meta: {
+        inMenu: true,
+        titleKey: "chronos.amendLessonOverview.menu_title",
+        icon: "mdi-grid",
+      },
+    },
   ],
 };
diff --git a/aleksis/apps/chronos/managers.py b/aleksis/apps/chronos/managers.py
index a2fc76acb785ea78c9bb709137852b5c65c0e1c9..ba620386bfcb59d31049ff4b5c7a2d89f7f01fd2 100644
--- a/aleksis/apps/chronos/managers.py
+++ b/aleksis/apps/chronos/managers.py
@@ -895,3 +895,16 @@ class LessonEventQuerySet(PolymorphicQuerySet):
         return self.filter(
             Q(teachers=person) | Q(groups__members=person) | Q(pk__in=amended)
         ).distinct()
+
+    def affected_by_absences(self, datetime_start: datetime, datetime_end: datetime):
+        return self.filter(
+            ((Q(teachers__kolego_absences__datetime_start__gte=datetime_start)
+              & Q(teachers__kolego_absences__datetime_start__lte=datetime_end))
+             | (Q(teachers__kolego_absences__datetime_end__gte=datetime_start)
+                & Q(teachers__kolego_absences__datetime_end__lte=datetime_end))
+             )
+            & Q(teachers__kolego_absences__datetime_start__lte=F("datetime_end"))
+            & Q(teachers__kolego_absences__datetime_end__gte=F("datetime_start"))
+            & Q(amends__isnull=True)
+            & Q(amended_by__isnull=True)
+        )
diff --git a/aleksis/apps/chronos/models.py b/aleksis/apps/chronos/models.py
index 0587381d7139025f6a4d4dc2c55225429819f180..c501552c2ce8a450500af60c85ba8d5ece857aa1 100644
--- a/aleksis/apps/chronos/models.py
+++ b/aleksis/apps/chronos/models.py
@@ -11,7 +11,7 @@ from django.contrib.contenttypes.models import ContentType
 from django.core.exceptions import ValidationError
 from django.core.validators import MinValueValidator
 from django.db import models
-from django.db.models import Max, Min, Q
+from django.db.models import F, Max, Min, Q
 from django.db.models.functions import Coalesce
 from django.dispatch import receiver
 from django.forms import Media
@@ -1424,7 +1424,7 @@ class LessonEvent(CalendarEvent):
 
     @property
     def subject_name_with_amends(self: LessonEvent) -> str:
-        my_subject = self.subject.name
+        my_subject = self.subject.name if self.subject else ""
         amended_subject = self.real_amends.subject.name if self.amends else ""
 
         if my_subject and amended_subject:
@@ -1543,6 +1543,10 @@ class LessonEvent(CalendarEvent):
         if params:
             obj_id = int(params.get("id", 0))
             type_ = params.get("type", None)
+            prefetch_absences = params.get("prefetch_absences", False)
+
+            if prefetch_absences:
+                objs = objs.prefetch_related("teachers__kolego_absences")
 
             if type_ and obj_id:
                 if type_ == "TEACHER":
@@ -1553,6 +1557,42 @@ class LessonEvent(CalendarEvent):
                     return objs.for_room(obj_id)
         return objs.for_person(request.user.person)
 
+    @classmethod
+    def get_for_substitution_overview(cls, obj_type: str, obj_id: str, date_start: datetime, date_end: datetime, request: HttpRequest) -> list:
+        """Get all the amended lessons for an object and a time frame.
+
+        obj_type may be one of TEACHER, GROUP, ROOM, COURSE
+        """
+
+        # 1. Find all LessonEvents for all Lessons of this Group in this date range and which are not themselves amending another lessonEvent
+
+        events = LessonEvent.get_single_events(date_start, date_end, request, {"type": obj_type, "id": obj_id, "not_amending": True, "prefetch_absences": True}, with_reference_object=True)
+        # (1.5 filter them by permissions)
+        ...
+
+        # 2. For each lessonEvent → check if there are any teachers with absences that overlap the lesson & if yes, check if there is already an amendment for that lesson
+        # if so, add it to a list, if not, create a new one (no dummy creation here possible since teachers is a m2m field)
+
+        amended_lessons = []
+
+        for event in events:
+            reference_obj = event["REFERENCE_OBJECT"]
+
+            affected_teachers = reference_obj.teachers.filter(Q(kolego_absences__datetime_start__lte=event["DTEND"].dt)
+                                                              & Q(kolego_absences__datetime_end__gte=event["DTSTART"].dt))
+
+            if affected_teachers.exists():
+                obj, created = LessonEvent.objects.update_or_create(
+                    amends=reference_obj,
+                    datetime_start=event["DTSTART"].dt,
+                    datetime_end=event["DTEND"].dt,
+                )
+                if created:
+                    obj.teachers.set(reference_obj.teachers.exclude(pk__in=affected_teachers))
+                amended_lessons.append(obj)
+
+        return amended_lessons
+
     class Meta:
         verbose_name = _("Lesson Event")
         verbose_name_plural = _("Lesson Events")
diff --git a/aleksis/apps/chronos/schema/__init__.py b/aleksis/apps/chronos/schema/__init__.py
index f7cc25ff46c7fe7018876cc782fb6ad4e92e4eca..c2a3e6fd4d33b2ee7298edeb7a6fa9e948f84016 100644
--- a/aleksis/apps/chronos/schema/__init__.py
+++ b/aleksis/apps/chronos/schema/__init__.py
@@ -1,12 +1,18 @@
-from datetime import timezone
+from datetime import date, datetime, timezone
+
+from functools import reduce
+from operator import and_
+from django.db.models import F, ManyToManyField, OuterRef, Subquery, Q, Prefetch
 
 import graphene
 from graphene_django import DjangoObjectType
-from graphene_django_cud.mutations import DjangoCreateMutation, DjangoPatchMutation
+from graphene_django_cud.mutations import DjangoBatchPatchMutation, DjangoCreateMutation, DjangoPatchMutation
 
 from aleksis.core.models import CalendarEvent, Group, Person, Room
 from aleksis.core.schema.base import DeleteMutation
 
+from aleksis.apps.kolego.models import Absence
+
 from ..models import LessonEvent
 from ..util.chronos_helpers import get_classes, get_rooms, get_teachers
 
@@ -53,11 +59,32 @@ class LessonEventType(DjangoObjectType):
             "teachers",
             "groups",
             "rooms",
+            "course",
             "cancelled",
             "comment",
         )
 
 
+class LessonEventTypeWithRealAmends(DjangoObjectType):
+    class Meta:
+        model = LessonEvent
+        fields = (
+            "id",
+            "amends",
+            "datetime_start",
+            "datetime_end",
+            "subject",
+            "teachers",
+            "groups",
+            "rooms",
+            "course",
+            "cancelled",
+            "comment",
+        )
+
+    real_amends = graphene.Field(LessonEventType, required=False)
+
+
 class DatetimeTimezoneMixin:
     """Handle datetimes for mutations with CalendarEvent objects.
 
@@ -114,6 +141,13 @@ class AmendLessonPatchMutation(DatetimeTimezoneMixin, DjangoPatchMutation):
         only_fields = ("subject", "teachers", "groups", "rooms", "cancelled", "comment")
 
 
+class AmendLessonBatchPatchMutation(DjangoBatchPatchMutation):
+    class Meta:
+        model = LessonEvent
+        permissions = ("chronos.edit_substitution_rule",)
+        only_fields = ("id", "subject", "teachers", "groups", "rooms", "cancelled", "comment")
+
+
 class AmendLessonDeleteMutation(DeleteMutation):
     klass = LessonEvent
     permission_required = "chronos.edit_substitution_rule"
@@ -145,6 +179,11 @@ class Query(graphene.ObjectType):
     timetable_rooms = graphene.List(TimetableRoomType)
     available_timetables = graphene.List(TimetableObjectType)
 
+    amended_lessons_from_absences = graphene.List(
+        LessonEventTypeWithRealAmends,
+        filters=graphene.JSONString(required=True),
+    )
+
     def resolve_timetable_teachers(self, info, **kwargs):
         return get_teachers(info.context.user)
 
@@ -186,8 +225,21 @@ class Query(graphene.ObjectType):
 
         return all_timetables
 
+    def resolve_amended_lessons_from_absences(root, info, filters, **kwargs):
+        if isinstance(filters, str):
+            filters = json.loads(filters)
+
+        datetime_start = datetime.combine(date.fromisoformat(filters.get("date_start", datetime.now().date().isoformat())) , datetime.min.time())
+        datetime_end = datetime.combine(date.fromisoformat(filters.get("date_end", datetime.now().date().isoformat())), datetime.max.time())
+
+        group_id = filters.get("group_id")
+
+        # TODO: later on, allow getting amended lessons for other types than courses, e.g. groups or persons
+        return LessonEvent.get_for_substitution_overview("GROUP", group_id, datetime_start, datetime_end, info.context)
+
 
 class Mutation(graphene.ObjectType):
     create_amend_lesson = AmendLessonCreateMutation.Field()
     patch_amend_lesson = AmendLessonPatchMutation.Field()
+    batch_patch_amend_lessons = AmendLessonBatchPatchMutation.Field()
     delete_amend_lesson = AmendLessonDeleteMutation.Field()
diff --git a/pyproject.toml b/pyproject.toml
index dc673aaad89e0b5f31ef65f6cc18422889cd9a19..aa02408ec2a8205863904e845e1e5dcdcdd5e48e 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -54,6 +54,7 @@ calendarweek = "^0.5.0"
 aleksis-core = "^4.0.0.dev2"
 aleksis-app-resint = "^4.0.0.dev1"
 aleksis-app-cursus = "^0.1.dev0"
+aleksis-app-kolego = "^0.1.dev0"
 
 
 [tool.poetry.plugins."aleksis.app"]