diff --git a/aleksis/apps/alsijil/menus.py b/aleksis/apps/alsijil/menus.py
index a3ec5e9cc443a951ca5ddf4803361bd29e0637f9..d20c88b567ad7d4feb86231eafa4e35d880f9e1c 100644
--- a/aleksis/apps/alsijil/menus.py
+++ b/aleksis/apps/alsijil/menus.py
@@ -24,6 +24,18 @@ MENUS = {
                     "icon": "view_week",
                     "validators": ["menu_generator.validators.is_authenticated"],
                 },
+                {
+                    "name": _("My overview"),
+                    "url": "overview_me",
+                    "icon": "insert_chart",
+                    "validators": ["menu_generator.validators.is_authenticated"],
+                },
+                {
+                    "name": _("My students"),
+                    "url": "my_students",
+                    "icon": "people",
+                    "validators": ["menu_generator.validators.is_authenticated"],
+                },
                 {
                     "name": _("Register absence"),
                     "url": "register_absence",
diff --git a/aleksis/apps/alsijil/models.py b/aleksis/apps/alsijil/models.py
index 83107c781f4169095b8f5774a0c078564b29fbc1..721648bc4f52ddb4728de84f21319635ee9a014f 100644
--- a/aleksis/apps/alsijil/models.py
+++ b/aleksis/apps/alsijil/models.py
@@ -77,6 +77,9 @@ class PersonalNote(ExtensibleModel, WeekRelatedMixin):
     def save(self, *args, **kwargs):
         if self.excuse_type:
             self.excused = True
+        if not self.absent:
+            self.excused = False
+            self.excuse_type = None
         super().save(*args, **kwargs)
 
     class Meta:
diff --git a/aleksis/apps/alsijil/templates/alsijil/class_register/person.html b/aleksis/apps/alsijil/templates/alsijil/class_register/person.html
new file mode 100644
index 0000000000000000000000000000000000000000..5a442b81c4fbb2956034bb26dc1f7c98ccbab4f8
--- /dev/null
+++ b/aleksis/apps/alsijil/templates/alsijil/class_register/person.html
@@ -0,0 +1,202 @@
+{# -*- engine:django -*- #}
+{% extends "core/base.html" %}
+{% load data_helpers %}
+{% load week_helpers %}
+{% load i18n %}
+
+{% block browser_title %}{% blocktrans %}Class register: person{% endblocktrans %}{% endblock %}
+
+
+{% block page_title %}
+  {% blocktrans with person=person %}
+    Class register overview for {{ person }}
+  {% endblocktrans %}
+{% endblock %}
+
+{% block content %}
+  <div class="row">
+  <div class="col s12 m12 l6">
+    <h5>{% trans "Unexcused absences" %}</h5>
+
+    <ul class="collection">
+      {% for note in unexcused_absences %}
+        {% weekday_to_date note.calendar_week note.lesson_period.period.weekday as note_date %}
+        <li class="collection-item">
+          <form action="" method="post" class="right hide-on-small-only" style="margin-top: -7px;">
+            {% csrf_token %}
+            {% trans "Mark as" %}
+            <input type="hidden" value="{{ note.pk }}" name="personal_note">
+            {% include "alsijil/partials/mark_as_buttons.html" %}
+          </form>
+          <i class="material-icons left red-text">warning</i>
+          <p class="no-margin">
+            <a href="{% url "lesson_by_week_and_period" note.year note.week note.lesson_period.pk %}">{{ note_date }}, {{ note.lesson_period }}</a>
+          </p>
+          {% if note.remarks %}
+            <p class="no-margin"><em>{{ note.remarks }}</em></p>
+          {% endif %}
+          <form action="" method="post" class="hide-on-med-and-up">
+            {% csrf_token %}
+            {% trans "Mark as" %}
+            <input type="hidden" value="{{ note.pk }}" name="personal_note">
+            {% include "alsijil/partials/mark_as_buttons.html" %}
+          </form>
+        </li>
+      {% empty %}
+        <li class="collection-item flow-text">
+          {% trans "There are unexcused lessons." %}
+        </li>
+      {% endfor %}
+    </ul>
+    <h5>{% trans "Statistics on absences, tardiness and remarks" %}</h5>
+    <ul class="collapsible">
+      {% for school_term, stat in stats %}
+        <li {% if forloop.first %}class="active"{% endif %}>
+          <div class="collapsible-header">
+            <i class="material-icons">date_range</i>{{ school_term }}</div>
+          <div class="collapsible-body">
+            <table>
+              <tr>
+                <th colspan="2">{% trans 'Absences' %}</th>
+                <td>{{ stat.absences_count }}</td>
+              </tr>
+              <tr>
+                <td rowspan="{{ excuse_types.count|add:2 }}" class="hide-on-small-only">{% trans "thereof" %}</td>
+                <td rowspan="{{ excuse_types.count|add:2 }}" class="hide-on-med-and-up"></td>
+                <th class="truncate">{% trans 'Excused' %}</th>
+                <td>{{ stat.excused }}</td>
+              </tr>
+              {% for excuse_type in excuse_types %}
+                <th>{{ excuse_type.name }}</th>
+                <td>{{ stat|get_dict:excuse_type.count_label }}</td>
+              {% endfor %}
+              <tr>
+                <th>{% trans 'Unexcused' %}</th>
+                <td>{{ stat.unexcused }}</td>
+              </tr>
+              <tr>
+                <th colspan="2">{% trans 'Tardiness' %}</th>
+                <td>{{ stat.tardiness }}'</td>
+              </tr>
+              {% for extra_mark in extra_marks %}
+                <tr>
+                  <th colspan="2">{{ extra_mark.name }}</th>
+                  <td>{{ stat|get_dict:extra_mark.count_label }}</td>
+                </tr>
+              {% endfor %}
+            </table>
+          </div>
+        </li>
+      {% endfor %}
+    </ul>
+  </div>
+  <div class="col s12 m12 l6">
+    <h5>{% trans "Relevant personal notes" %}</h5>
+    <ul class="collapsible">
+      <li>
+        <div>
+          <ul>
+            {% for note in personal_notes %}
+              {% ifchanged note.lesson_period.lesson.validity.school_term %}</ul></div></li>
+                <li {% if forloop.first %}class="active"{% endif %}>
+                <div class="collapsible-header"><i
+                        class="material-icons">date_range</i>{{ note.lesson_period.lesson.validity.school_term }}</div>
+                <div class="collapsible-body">
+                <ul class="collection">
+              {% endifchanged %}
+
+              {% ifchanged note.week %}
+                <li class="collection-item">
+                  <strong>{% blocktrans with week=note.week %}Week {{ week }}{% endblocktrans %}</strong>
+                </li>
+              {% endifchanged %}
+              {% weekday_to_date note.calendar_week note.lesson_period.period.weekday as note_date %}
+              {% ifchanged note_date %}
+                <li class="collection-item">
+                  <form action="" method="post" class="right hide-on-small-only" style="margin-top: -7px;">
+                    {% csrf_token %}
+                    {% trans "Mark all as" %}
+                    <input type="hidden" value="{{ note_date|date:"Y-m-d" }}" name="date">
+                    {% include "alsijil/partials/mark_as_buttons.html" %}
+                  </form>
+                  <i class="material-icons left">schedule</i>
+                  {{ note_date }}
+
+                  <form action="" method="post" class="hide-on-med-and-up">
+                    {% csrf_token %}
+                    {% trans "Mark all as" %}
+                    <input type="hidden" value="{{ note_date|date:"Y-m-d" }}" name="date">
+                    {% include "alsijil/partials/mark_as_buttons.html" %}
+                  </form>
+                </li>
+              {% endifchanged %}
+
+              <li class="collection-item">
+                <div class="row no-margin">
+                  <div class="col s2 m1">
+                    {{ note.lesson_period.period.period }}.
+                  </div>
+
+                  <div class="col s10 m4">
+                    <i class="material-icons left">event_note</i>
+                    <a href="{% url "lesson_by_week_and_period" note.year note.week note.lesson_period.pk %}">
+                      {{ note.lesson_period.get_subject.name }}<br/>
+                      {{ note.lesson_period.get_teacher_names }}
+                    </a>
+                  </div>
+
+                  <div class="col s12 m7 no-padding">
+                    {% if note.absent and not note.excused %}
+                      <form action="" method="post" class="right hide-on-small-only" style="margin-top: -7px;">
+                        {% csrf_token %}
+                        {% trans "Mark as" %}
+                        <input type="hidden" value="{{ note.pk }}" name="personal_note">
+                        {% include "alsijil/partials/mark_as_buttons.html" %}
+                      </form>
+                    {% endif %}
+
+                    {% if note.absent %}
+                      <div class="chip red white-text">
+                        {% trans 'Absent' %}
+                      </div>
+                    {% endif %}
+                    {% if note.excused %}
+                      <div class="chip green white-text">
+                        {% if note.excuse_type %}
+                          {{ note.excuse_type.name }}
+                        {% else %}
+                          {% trans 'Excused' %}
+                        {% endif %}
+                      </div>
+                    {% endif %}
+
+                    {% if note.late %}
+                      <div class="chip orange white-text">
+                        {% blocktrans with late=note.late %}{{ late }}' late{% endblocktrans %}
+                      </div>
+                    {% endif %}
+
+                    {% for extra_mark in note.extra_marks.all %}
+                      <div class="chip">{{ extra_mark.name }}</div>
+                    {% endfor %}
+
+                    <em>{{ note.remarks }}</em>
+
+                  </div>
+                  <div class="col s12 hide-on-med-and-up">
+                    {% if note.absent and not note.excused %}
+                      <form action="" method="post">
+                        {% csrf_token %}
+                        {% trans "Mark as" %}
+                        <input type="hidden" value="{{ note.pk }}" name="personal_note">
+                        {% include "alsijil/partials/mark_as_buttons.html" %}
+                      </form>
+                    {% endif %}
+                  </div>
+              </li>
+            {% endfor %}
+            </li>
+            </ul>
+            </div>
+  </div>
+{% endblock %}
diff --git a/aleksis/apps/alsijil/templates/alsijil/class_register/persons.html b/aleksis/apps/alsijil/templates/alsijil/class_register/persons.html
new file mode 100644
index 0000000000000000000000000000000000000000..c3f5e35d48991bafd37ffdc3def7f445d1400247
--- /dev/null
+++ b/aleksis/apps/alsijil/templates/alsijil/class_register/persons.html
@@ -0,0 +1,26 @@
+{# -*- engine:django -*- #}
+{% extends "core/base.html" %}
+{% load data_helpers %}
+{% load week_helpers %}
+{% load i18n %}
+
+{% block browser_title %}{% blocktrans %}My students{% endblocktrans %}{% endblock %}
+
+
+{% block page_title %}
+  {% blocktrans %}My students{% endblocktrans %}
+{% endblock %}
+
+{% block content %}
+  <div class="collection">
+    {% for person in persons %}
+      <a class="collection-item" href="{% url "overview_person" person.pk %}">
+      {{ person }}
+      </a>
+    {% empty %}
+      <li class="collection-item flow-text">
+        {% blocktrans %}No students available.{% endblocktrans %}
+      </li>
+    {% endfor %}
+  </div>
+{% endblock %}
diff --git a/aleksis/apps/alsijil/templates/alsijil/class_register/week_view.html b/aleksis/apps/alsijil/templates/alsijil/class_register/week_view.html
index d0761f8102f60e1ea899a8b1ba1d11c1e2402535..ea549f7f15783769f79a9d598304b856481adb18 100644
--- a/aleksis/apps/alsijil/templates/alsijil/class_register/week_view.html
+++ b/aleksis/apps/alsijil/templates/alsijil/class_register/week_view.html
@@ -35,7 +35,8 @@
 
 
   <div class="row">
-    <h4 class="col s12 m6">{% blocktrans with el=el week=week.week %}CW {{ week }}: {{ instance }}{% endblocktrans %} </h4>
+    <h4 class="col s12 m6">{% blocktrans with el=el week=week.week %}CW {{ week }}:
+      {{ instance }}{% endblocktrans %} </h4>
     {% include "chronos/partials/week_select.html" with wanted_week=week %}
   </div>
 
@@ -111,7 +112,9 @@
               {% blocktrans %}Personal notes{% endblocktrans %}
             </span>
             {% for person in persons %}
-              <h5 class="card-title">{{ person.person.full_name }}</h5>
+              <h5 class="card-title">
+                <a href="{% url "overview_person" person.person.pk %}">{{ person.person.full_name }}</a>
+              </h5>
               <p class="card-text">
                 {% trans "Absent" %}: {{ person.person.absences_count }}
                 ({{ person.person.unexcused_count }} {% trans "unexcused" %})
diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/mark_as_buttons.html b/aleksis/apps/alsijil/templates/alsijil/partials/mark_as_buttons.html
new file mode 100644
index 0000000000000000000000000000000000000000..5b198afa4bceea55c2b749fa8b3f3b8d88b335e8
--- /dev/null
+++ b/aleksis/apps/alsijil/templates/alsijil/partials/mark_as_buttons.html
@@ -0,0 +1,12 @@
+{% load i18n %}
+<button type="submit" class="btn-flat tooltipped" name="excuse_type" value="e" title="{% trans "Excused" %}"
+        data-position="bottom" data-tooltip="{% trans "Excused" %}" style="width: 50px;">
+  {% trans "e" %}
+</button>
+{% for excuse_type in excuse_types %}
+  <button type="submit" class="btn-flat tooltipped" value="{{ excuse_type.pk }}" name="excuse_type"
+          title="{{ excuse_type.name }}" data-position="bottom" data-tooltip="{{ excuse_type.name }}"
+          style="width: 50px;">
+    {{ excuse_type.short_name }}
+  </button>
+{% endfor %}
diff --git a/aleksis/apps/alsijil/templates/alsijil/print/full_register.html b/aleksis/apps/alsijil/templates/alsijil/print/full_register.html
index 373ae6a88f6f42953dfa0b4ffeceb8a26716104b..03b75de7b70508885bf06f35e42d1058a5c80b1a 100644
--- a/aleksis/apps/alsijil/templates/alsijil/print/full_register.html
+++ b/aleksis/apps/alsijil/templates/alsijil/print/full_register.html
@@ -319,7 +319,7 @@
       {% for note in person.personal_notes.all %}
         {% if note.lesson_period in lesson_periods %}
           {% if note.absent or note.late or note.remarks or note.extra_marks.all %}
-            {% period_to_date note.week note.lesson_period.period as note_date %}
+              {% weekday_to_date note.calendar_week note.lesson_period.period.weekday as note_date %}
             <tr>
               <td>{{ note_date }}</td>
               <td>{{ note.lesson_period.period.period }}</td>
diff --git a/aleksis/apps/alsijil/urls.py b/aleksis/apps/alsijil/urls.py
index 7e7139c6c26fe7aa600b6b311b55ae731389c13b..0482571bd3cd9cf7c7da4a15b4cd7fc3e0a58c36 100644
--- a/aleksis/apps/alsijil/urls.py
+++ b/aleksis/apps/alsijil/urls.py
@@ -26,6 +26,9 @@ urlpatterns = [
     path(
         "print/group/<int:id_>", views.full_register_group, name="full_register_group"
     ),
+    path("persons/", views.my_students, name="my_students"),
+    path("persons/<int:id_>/", views.overview_person, name="overview_person"),
+    path("me/", views.overview_person, name="overview_me"),
     path("absence/new", views.register_absence, name="register_absence"),
     path("extra_marks/", views.ExtraMarkListView.as_view(), name="extra_marks"),
     path(
diff --git a/aleksis/apps/alsijil/views.py b/aleksis/apps/alsijil/views.py
index efa96737739abae615138d73f201e7ba36cc4591..f9840a124ee64626238b77031039837b96525554 100644
--- a/aleksis/apps/alsijil/views.py
+++ b/aleksis/apps/alsijil/views.py
@@ -20,7 +20,7 @@ from aleksis.apps.chronos.util.date import get_weeks_for_year, week_weekday_to_d
 from aleksis.core.mixins import AdvancedCreateView, AdvancedDeleteView, AdvancedEditView
 from aleksis.core.models import Group, Person, SchoolTerm
 from aleksis.core.util import messages
-from aleksis.core.util.core_helpers import get_site_preferences
+from aleksis.core.util.core_helpers import get_site_preferences, objectgetter_optional
 
 from .forms import (
     ExcuseTypeForm,
@@ -30,7 +30,7 @@ from .forms import (
     RegisterAbsenceForm,
     SelectForm,
 )
-from .models import ExcuseType, ExtraMark, LessonDocumentation
+from .models import ExcuseType, ExtraMark, LessonDocumentation, PersonalNote
 from .tables import ExcuseTypeTable, ExtraMarkTable
 
 
@@ -458,6 +458,141 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
     return render(request, "alsijil/print/full_register.html", context)
 
 
+def my_students(request: HttpRequest) -> HttpResponse:
+    context = {}
+    relevant_groups = (
+        Group.objects.for_current_school_term_or_all()
+        .annotate(lessons_count=Count("lessons"))
+        .filter(lessons_count__gt=0, owners=request.user.person)
+    )
+    persons = Person.objects.filter(member_of__in=relevant_groups)
+    context["persons"] = persons
+    return render(request, "alsijil/class_register/persons.html", context)
+
+
+def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse:
+    context = {}
+    person = objectgetter_optional(
+        Person, default="request.user.person", default_eval=True
+    )(request, id_)
+    context["person"] = person
+
+    if request.method == "POST":
+        if request.POST.get("excuse_type"):
+            # Get excuse type
+            excuse_type = request.POST["excuse_type"]
+            found = False
+            if excuse_type == "e":
+                excuse_type = None
+                found = True
+            else:
+                try:
+                    excuse_type = ExcuseType.objects.get(pk=int(excuse_type))
+                    found = True
+                except (ExcuseType.DoesNotExist, ValueError):
+                    pass
+
+            if found:
+                if request.POST.get("date"):
+                    # Mark absences on date as excused
+                    try:
+                        date = datetime.strptime(
+                            request.POST["date"], "%Y-%m-%d"
+                        ).date()
+
+                        notes = person.personal_notes.filter(
+                            week=date.isocalendar()[1],
+                            lesson_period__period__weekday=date.weekday(),
+                            lesson_period__lesson__validity__date_start__lte=date,
+                            lesson_period__lesson__validity__date_end__gte=date,
+                            absent=True,
+                            excused=False,
+                        )
+                        notes.update(excused=True, excuse_type=excuse_type)
+                        messages.success(
+                            request, _("The absences have been marked as excused.")
+                        )
+                    except ValueError:
+                        pass
+                elif request.POST.get("personal_note"):
+                    # Mark specific absence as excused
+                    try:
+                        note = PersonalNote.objects.get(
+                            pk=int(request.POST["personal_note"])
+                        )
+                        if note.absent:
+                            note.excused = True
+                            note.excuse_type = excuse_type
+                            note.save()
+                            messages.success(
+                                request, _("The absence has been marked as excused.")
+                            )
+                    except (PersonalNote.DoesNotExist, ValueError):
+                        pass
+
+                person.refresh_from_db()
+
+    unexcused_absences = person.personal_notes.filter(absent=True, excused=False)
+    context["unexcused_absences"] = unexcused_absences
+
+    personal_notes = person.personal_notes.filter(
+        Q(absent=True) | Q(late__gt=0) | ~Q(remarks="") | Q(extra_marks__isnull=False)
+    ).order_by(
+        "-lesson_period__lesson__validity__date_start",
+        "-week",
+        "lesson_period__period__weekday",
+        "lesson_period__period__period",
+    )
+    context["personal_notes"] = personal_notes
+    context["excuse_types"] = ExcuseType.objects.all()
+
+    school_terms = SchoolTerm.objects.all().order_by("-date_start")
+    stats = []
+    for school_term in school_terms:
+        stat = {}
+        personal_notes = PersonalNote.objects.filter(
+            person=person, lesson_period__lesson__validity__school_term=school_term
+        )
+
+        if not personal_notes.exists():
+            continue
+
+        stat.update(
+            personal_notes.filter(absent=True).aggregate(absences_count=Count("absent"))
+        )
+        stat.update(
+            personal_notes.filter(
+                absent=True, excused=True, excuse_type__isnull=True
+            ).aggregate(excused=Count("absent"))
+        )
+        stat.update(
+            personal_notes.filter(absent=True, excused=False).aggregate(
+                unexcused=Count("absent")
+            )
+        )
+        stat.update(personal_notes.aggregate(tardiness=Sum("late")))
+
+        for extra_mark in ExtraMark.objects.all():
+            stat.update(
+                personal_notes.filter(extra_marks=extra_mark).aggregate(
+                    **{extra_mark.count_label: Count("pk")}
+                )
+            )
+
+        for excuse_type in ExcuseType.objects.all():
+            stat.update(
+                personal_notes.filter(absent=True, excuse_type=excuse_type).aggregate(
+                    **{excuse_type.count_label: Count("absent")}
+                )
+            )
+
+        stats.append((school_term, stat))
+    context["stats"] = stats
+    context["excuse_types"] = ExcuseType.objects.all()
+    context["extra_marks"] = ExtraMark.objects.all()
+    return render(request, "alsijil/class_register/person.html", context)
+
+
 def register_absence(request: HttpRequest) -> HttpResponse:
     context = {}