diff --git a/core/src/main/java/se/su/dsv/scipro/CoreConfig.java b/core/src/main/java/se/su/dsv/scipro/CoreConfig.java
index a6ec1b8ffe..918df6478f 100644
--- a/core/src/main/java/se/su/dsv/scipro/CoreConfig.java
+++ b/core/src/main/java/se/su/dsv/scipro/CoreConfig.java
@@ -744,9 +744,10 @@ public class CoreConfig {
     @Bean
     public ReflectionServiceImpl reflectionService(
             AuthorRepository authorRepository,
-            FinalSeminarServiceImpl finalSeminarService)
+            FinalSeminarServiceImpl finalSeminarService,
+            EventBus eventBus)
     {
-        return new ReflectionServiceImpl(authorRepository, finalSeminarService);
+        return new ReflectionServiceImpl(authorRepository, finalSeminarService, eventBus);
     }
 
     @Bean
diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/ProjectEvent.java b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/ProjectEvent.java
index a44a3760be..ae72d48f16 100755
--- a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/ProjectEvent.java
+++ b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/ProjectEvent.java
@@ -23,7 +23,8 @@ public class ProjectEvent extends NotificationEvent {
         ROUGH_DRAFT_APPROVAL_APPROVED, ROUGH_DRAFT_APPROVAL_REJECTED, REVIEWER_GRADING_REPORT_SUBMITTED,
         ONE_YEAR_PASSED_FROM_LATEST_ANNUAL_REVIEW, SUPERVISOR_GRADING_INITIAL_ASSESSMENT_DONE,
         EXPORTED_SUCCESS, REVIEWER_GRADING_INITIAL_ASSESSMENT_DONE, FIRST_MEETING, OPPOSITION_FAILED,
-        PARTICIPATION_APPROVED, COMPLETED, PARTICIPATION_FAILED
+        PARTICIPATION_APPROVED, COMPLETED, PARTICIPATION_FAILED, REFLECTION_IMPROVEMENTS_REQUESTED,
+        REFLECTION_IMPROVEMENTS_SUBMITTED
     }
 
     @Basic
diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/notifications.properties b/core/src/main/java/se/su/dsv/scipro/notifications/notifications.properties
index a972eac30e..c5cb11b76a 100755
--- a/core/src/main/java/se/su/dsv/scipro/notifications/notifications.properties
+++ b/core/src/main/java/se/su/dsv/scipro/notifications/notifications.properties
@@ -85,6 +85,13 @@ PROJECT.PARTICIPATION_APPROVED.body = Your active participation on {0} has been
 PROJECT.PARTICIPATION_FAILED.title = Your active participation on {1} did not meet the minimum requirements.
 PROJECT.PARTICIPATION_FAILED.body = Your active participation did not meet the minimum requirements set, and you will \
   have to be an active participant on a different final seminar to pass this step.
+PROJECT.REFLECTION_IMPROVEMENTS_REQUESTED.title = Reflection improvements requested
+PROJECT.REFLECTION_IMPROVEMENTS_REQUESTED.body = The supervisor has deemed that the reflection submitted does not meet \
+  the minimum requirements and has requested improvements. Please log into SciPro and submit a new reflection. \
+  Their comments can be seen below:\n\n{0}
+PROJECT.REFLECTION_IMPROVEMENTS_SUBMITTED.title = Reflection improvements submitted
+PROJECT.REFLECTION_IMPROVEMENTS_SUBMITTED.body = The reflection improvements have been submitted. \
+  \n\n{0}
 
 FORUM.NEW_FORUM_POST.title = Forum post: {2}
 FORUM.NEW_FORUM_POST.body = New forum post submitted:<br /><br />{0}
diff --git a/core/src/main/java/se/su/dsv/scipro/project/Author.java b/core/src/main/java/se/su/dsv/scipro/project/Author.java
index 8adaa5fed3..96ec7ce284 100644
--- a/core/src/main/java/se/su/dsv/scipro/project/Author.java
+++ b/core/src/main/java/se/su/dsv/scipro/project/Author.java
@@ -5,6 +5,8 @@ import jakarta.persistence.Column;
 import jakarta.persistence.Embeddable;
 import jakarta.persistence.EmbeddedId;
 import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
 import jakarta.persistence.JoinColumn;
 import jakarta.persistence.ManyToOne;
 import jakarta.persistence.MapsId;
@@ -30,6 +32,15 @@ public class Author {
     @Column(name = "reflection")
     private String reflection;
 
+    @Basic
+    @Enumerated(EnumType.STRING)
+    @Column(name = "reflection_status")
+    private ReflectionStatus reflectionStatus = ReflectionStatus.NOT_SUBMITTED;
+
+    @Basic
+    @Column(name = "reflection_comment_by_supervisor")
+    private String reflectionSupervisorComment;
+
     /**
      * If this author wants to be notified when a final seminar created
      * as long as they have not yet completed both an opposition and
@@ -85,6 +96,22 @@ public class Author {
         return user;
     }
 
+    public ReflectionStatus getReflectionStatus() {
+        return reflectionStatus;
+    }
+
+    public void setReflectionStatus(ReflectionStatus reflectionStatus) {
+        this.reflectionStatus = reflectionStatus;
+    }
+
+    public void setReflectionSupervisorComment(String reflectionSupervisorComment) {
+        this.reflectionSupervisorComment = reflectionSupervisorComment;
+    }
+
+    public String getReflectionSupervisorComment() {
+        return reflectionSupervisorComment;
+    }
+
     // ----------------------------------------------------------------------------------
     // Nested class
     // ----------------------------------------------------------------------------------
diff --git a/core/src/main/java/se/su/dsv/scipro/project/ReflectionStatus.java b/core/src/main/java/se/su/dsv/scipro/project/ReflectionStatus.java
new file mode 100644
index 0000000000..92b94cd7b6
--- /dev/null
+++ b/core/src/main/java/se/su/dsv/scipro/project/ReflectionStatus.java
@@ -0,0 +1,7 @@
+package se.su.dsv.scipro.project;
+
+public enum ReflectionStatus {
+    NOT_SUBMITTED,
+    SUBMITTED,
+    IMPROVEMENTS_NEEDED
+}
diff --git a/core/src/main/java/se/su/dsv/scipro/reflection/Reflection.java b/core/src/main/java/se/su/dsv/scipro/reflection/Reflection.java
new file mode 100644
index 0000000000..898d961a2c
--- /dev/null
+++ b/core/src/main/java/se/su/dsv/scipro/reflection/Reflection.java
@@ -0,0 +1,22 @@
+package se.su.dsv.scipro.reflection;
+
+public sealed interface Reflection {
+    boolean isSubmittable();
+
+    record NotSubmitted() implements Reflection {
+        @Override
+        public boolean isSubmittable() { return true; }
+    }
+
+    record Submitted(String reflection) implements Reflection {
+        @Override
+        public boolean isSubmittable() {
+            return false;
+        }
+    }
+
+    record ImprovementsNeeded(String oldReflection, String commentBySupervisor) implements Reflection {
+        @Override
+        public boolean isSubmittable() { return true; }
+    }
+}
diff --git a/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionImprovementsRequestedEvent.java b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionImprovementsRequestedEvent.java
new file mode 100644
index 0000000000..07d8811f99
--- /dev/null
+++ b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionImprovementsRequestedEvent.java
@@ -0,0 +1,7 @@
+package se.su.dsv.scipro.reflection;
+
+import se.su.dsv.scipro.project.Project;
+import se.su.dsv.scipro.system.User;
+
+public record ReflectionImprovementsRequestedEvent(Project project, User author, String supervisorComment) {
+}
diff --git a/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionImprovementsSubmittedEvent.java b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionImprovementsSubmittedEvent.java
new file mode 100644
index 0000000000..ce43d5eed4
--- /dev/null
+++ b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionImprovementsSubmittedEvent.java
@@ -0,0 +1,10 @@
+package se.su.dsv.scipro.reflection;
+
+import se.su.dsv.scipro.project.Project;
+import se.su.dsv.scipro.system.User;
+
+/**
+ * This event may be triggered by the supervisor if they edit the reflection after requesting improvements.
+ */
+public record ReflectionImprovementsSubmittedEvent(Project project, User author, String reflection) {
+}
diff --git a/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionService.java b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionService.java
index b4a206bf76..139dc9a6d9 100644
--- a/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionService.java
+++ b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionService.java
@@ -14,4 +14,15 @@ public interface ReflectionService {
      * @return the reflection, or {@code null} if none has been submitted
      */
     String getSubmittedReflection(Project project, User author);
+
+    /**
+     * Used by the supervisor when the currently submitted reflection does not meet the minimum requirements.
+     * This is done individually by author.
+     *
+     * @param author the author whose reflection does not meet the minimum requirements.
+     * @param supervisorComment feedback provided by the supervisor so the author knows what to improve.
+     */
+    void requestNewReflection(Project project, User author, String supervisorComment);
+
+    Reflection getReflection(Project project, User author);
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionServiceImpl.java
index bdc36bc904..73d934ca32 100644
--- a/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionServiceImpl.java
@@ -1,22 +1,32 @@
 package se.su.dsv.scipro.reflection;
 
+import com.google.common.eventbus.EventBus;
 import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.finalseminar.AuthorRepository;
 import se.su.dsv.scipro.finalseminar.FinalSeminarService;
 import se.su.dsv.scipro.project.Author;
 import se.su.dsv.scipro.project.Project;
+import se.su.dsv.scipro.project.ReflectionStatus;
 import se.su.dsv.scipro.system.User;
 
 import jakarta.inject.Inject;
 
+import java.util.Optional;
+
 public class ReflectionServiceImpl implements ReflectionService {
     private final AuthorRepository authorRepository;
     private final FinalSeminarService finalSeminarService;
+    private final EventBus eventBus;
 
     @Inject
-    public ReflectionServiceImpl(AuthorRepository authorRepository, FinalSeminarService finalSeminarService) {
+    public ReflectionServiceImpl(
+            AuthorRepository authorRepository,
+            FinalSeminarService finalSeminarService,
+            EventBus eventBus)
+    {
         this.authorRepository = authorRepository;
         this.finalSeminarService = finalSeminarService;
+        this.eventBus = eventBus;
     }
 
     @Override
@@ -25,10 +35,13 @@ public class ReflectionServiceImpl implements ReflectionService {
     }
 
     @Override
-    public boolean hasToFillInReflection(Project project, User author) {
-        boolean noReflectionSubmitted = authorRepository.findByProjectAndUser(project, author)
-                .map(Author::getReflection)
-                .isEmpty();
+    public boolean hasToFillInReflection(Project project, User user) {
+        Optional<Author> optionalAuthor = authorRepository.findByProjectAndUser(project, user);
+        if (optionalAuthor.isEmpty()) {
+            return false;
+        }
+        Author author = optionalAuthor.get();
+        boolean noReflectionSubmitted = author.getReflectionStatus() != ReflectionStatus.SUBMITTED;
         return hasReachedReflectionProcess(project) && noReflectionSubmitted;
     }
 
@@ -36,7 +49,13 @@ public class ReflectionServiceImpl implements ReflectionService {
     @Transactional
     public void submitReflection(Project project, User user, String reflection) {
         authorRepository.findByProjectAndUser(project, user)
-                .ifPresent(author -> author.setReflection(reflection));
+                .ifPresent(author -> {
+                    if (author.getReflectionStatus() == ReflectionStatus.IMPROVEMENTS_NEEDED) {
+                        eventBus.post(new ReflectionImprovementsSubmittedEvent(project, user, reflection));
+                    }
+                    author.setReflection(reflection);
+                    author.setReflectionStatus(ReflectionStatus.SUBMITTED);
+                });
     }
 
     @Override
@@ -45,4 +64,32 @@ public class ReflectionServiceImpl implements ReflectionService {
                 .map(Author::getReflection)
                 .orElse(null);
     }
+
+    @Override
+    @Transactional
+    public void requestNewReflection(Project project, User user, String supervisorComment) {
+        authorRepository.findByProjectAndUser(project, user)
+                .ifPresent(author -> {
+                    author.setReflectionStatus(ReflectionStatus.IMPROVEMENTS_NEEDED);
+                    author.setReflectionSupervisorComment(supervisorComment);
+                });
+        eventBus.post(new ReflectionImprovementsRequestedEvent(project, user, supervisorComment));
+    }
+
+    @Override
+    public Reflection getReflection(Project project, User author) {
+        return authorRepository.findByProjectAndUser(project, author)
+                .map(this::toReflection)
+                .orElseGet(Reflection.NotSubmitted::new);
+    }
+
+    private Reflection toReflection(Author author) {
+        return switch (author.getReflectionStatus()) {
+            case SUBMITTED -> new Reflection.Submitted(author.getReflection());
+            case IMPROVEMENTS_NEEDED -> new Reflection.ImprovementsNeeded(
+                    author.getReflection(),
+                    author.getReflectionSupervisorComment());
+            default -> new Reflection.NotSubmitted();
+        };
+    }
 }
diff --git a/core/src/main/resources/db/migration/V392_1__reflection_resubmission.sql b/core/src/main/resources/db/migration/V392_1__reflection_resubmission.sql
new file mode 100644
index 0000000000..d80e266c9d
--- /dev/null
+++ b/core/src/main/resources/db/migration/V392_1__reflection_resubmission.sql
@@ -0,0 +1,4 @@
+ALTER TABLE `project_user`
+    ADD COLUMN `reflection_status` VARCHAR(32) NOT NULL DEFAULT 'NOT_SUBMITTED';
+
+UPDATE `project_user` SET `reflection_status` = 'SUBMITTED' WHERE `reflection` IS NOT NULL;
diff --git a/core/src/main/resources/db/migration/V392_2__reflection_comment_by_supervisor.sql b/core/src/main/resources/db/migration/V392_2__reflection_comment_by_supervisor.sql
new file mode 100644
index 0000000000..f3cc5f2ce1
--- /dev/null
+++ b/core/src/main/resources/db/migration/V392_2__reflection_comment_by_supervisor.sql
@@ -0,0 +1 @@
+ALTER TABLE `project_user` ADD COLUMN `reflection_comment_by_supervisor` TEXT NULL;
diff --git a/core/src/test/java/se/su/dsv/scipro/reflection/ReflectionServiceTest.java b/core/src/test/java/se/su/dsv/scipro/reflection/ReflectionServiceTest.java
index 8d8d462e31..745def4bcd 100644
--- a/core/src/test/java/se/su/dsv/scipro/reflection/ReflectionServiceTest.java
+++ b/core/src/test/java/se/su/dsv/scipro/reflection/ReflectionServiceTest.java
@@ -101,6 +101,26 @@ public class ReflectionServiceTest extends IntegrationTest {
         assertTrue(reflectionService.hasReachedReflectionProcess(project));
     }
 
+    @Test
+    public void request_resubmission() {
+        LocalDate seminarDate = scheduleSeminar();
+        clock.setDate(seminarDate.plusDays(1));
+        assertTrue(reflectionService.hasToFillInReflection(project, author),
+                "After the final seminar the author should be required to submit a reflection");
+
+        String myReflection = "my reflection";
+        reflectionService.submitReflection(project, author, myReflection);
+        assertEquals(myReflection, reflectionService.getSubmittedReflection(project, author));
+        assertFalse(reflectionService.hasToFillInReflection(project, author),
+                "After submitting the initial reflection it should no longer be required");
+
+        reflectionService.requestNewReflection(project, author, "Very bad reflection");
+        assertTrue(reflectionService.hasToFillInReflection(project, author),
+                "After supervisor requests resubmission the author should now be required to submit a new reflection");
+        assertEquals(myReflection, reflectionService.getSubmittedReflection(project, author),
+                "The old reflection should be saved to make it easier for the student to update it");
+    }
+
     private LocalDate scheduleSeminar() {
         project.setFinalSeminarRuleExempted(true); // to bypass rough draft approval
         FinalSeminarDetails details = new FinalSeminarDetails("Zoom", false, 1, 1, Language.SWEDISH, Language.ENGLISH, "zoom id 123");
diff --git a/view/src/main/java/se/su/dsv/scipro/crosscutting/NotifyFailedReflection.java b/view/src/main/java/se/su/dsv/scipro/crosscutting/NotifyFailedReflection.java
new file mode 100644
index 0000000000..867703dde2
--- /dev/null
+++ b/view/src/main/java/se/su/dsv/scipro/crosscutting/NotifyFailedReflection.java
@@ -0,0 +1,46 @@
+package se.su.dsv.scipro.crosscutting;
+
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
+import jakarta.inject.Inject;
+import se.su.dsv.scipro.data.dataobjects.Member;
+import se.su.dsv.scipro.notifications.NotificationController;
+import se.su.dsv.scipro.notifications.dataobject.NotificationSource;
+import se.su.dsv.scipro.notifications.dataobject.ProjectEvent;
+import se.su.dsv.scipro.reflection.ReflectionImprovementsRequestedEvent;
+import se.su.dsv.scipro.reflection.ReflectionImprovementsSubmittedEvent;
+
+import java.util.Set;
+
+public class NotifyFailedReflection {
+    private final NotificationController notificationController;
+
+    @Inject
+    public NotifyFailedReflection(NotificationController notificationController, EventBus eventBus) {
+        this.notificationController = notificationController;
+        eventBus.register(this);
+    }
+
+    @Subscribe
+    public void reflectionImprovementsRequested(ReflectionImprovementsRequestedEvent event) {
+        NotificationSource source = new NotificationSource();
+        source.setMessage(event.supervisorComment());
+        notificationController.notifyCustomProject(
+                event.project(),
+                ProjectEvent.Event.REFLECTION_IMPROVEMENTS_REQUESTED,
+                source,
+                Set.of(new Member(event.author(), Member.Type.AUTHOR)));
+    }
+
+    @Subscribe
+    public void reflectionImprovementsSubmittted(ReflectionImprovementsSubmittedEvent event) {
+        NotificationSource source = new NotificationSource();
+        source.setMessage(event.reflection());
+        source.setAdditionalMessage(event.author().getFullName());
+        notificationController.notifyCustomProject(
+                event.project(),
+                ProjectEvent.Event.REFLECTION_IMPROVEMENTS_SUBMITTED,
+                source,
+                Set.of(new Member(event.project().getHeadSupervisor(), Member.Type.SUPERVISOR)));
+    }
+}
diff --git a/view/src/main/java/se/su/dsv/scipro/grading/CriteriaPanel.html b/view/src/main/java/se/su/dsv/scipro/grading/CriteriaPanel.html
index 079fb7b067..8794749252 100644
--- a/view/src/main/java/se/su/dsv/scipro/grading/CriteriaPanel.html
+++ b/view/src/main/java/se/su/dsv/scipro/grading/CriteriaPanel.html
@@ -49,10 +49,16 @@
                 </div>
             </wicket:fragment>
         </div>
-        <wicket:container wicket:id="reflection">
+        <div wicket:id="reflection">
+            <wicket:enclosure>
+                <div class="alert alert-danger">
+                    <h4 class="alert-heading">Improvements requested</h4>
+                    <wicket:container wicket:id="improvementsNeeded"/>
+                </div>
+            </wicket:enclosure>
             <a wicket:id="showReflection" href="#">View reflection</a>
             <div wicket:id="modal"></div>
-        </wicket:container>
+        </div>
     </fieldset>
 </wicket:panel>
 </body>
diff --git a/view/src/main/java/se/su/dsv/scipro/grading/CriteriaPanel.java b/view/src/main/java/se/su/dsv/scipro/grading/CriteriaPanel.java
index e5475c42ed..011cb74f9f 100644
--- a/view/src/main/java/se/su/dsv/scipro/grading/CriteriaPanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/grading/CriteriaPanel.java
@@ -30,10 +30,12 @@ import se.su.dsv.scipro.finalseminar.FinalSeminar;
 import se.su.dsv.scipro.finalseminar.FinalSeminarOpposition;
 import se.su.dsv.scipro.finalseminar.FinalSeminarService;
 import se.su.dsv.scipro.project.Project;
+import se.su.dsv.scipro.reflection.Reflection;
 import se.su.dsv.scipro.reflection.ReflectionService;
 import se.su.dsv.scipro.report.AbstractGradingCriterion;
 import se.su.dsv.scipro.report.GradingCriterion;
 import se.su.dsv.scipro.report.GradingCriterionPoint;
+import se.su.dsv.scipro.report.GradingReport;
 import se.su.dsv.scipro.report.SupervisorGradingReport;
 import se.su.dsv.scipro.system.Language;
 import se.su.dsv.scipro.system.User;
@@ -264,14 +266,33 @@ public class CriteriaPanel extends GenericPanel<SupervisorGradingReport> {
             super(id, author);
             this.gradingCriterion = gradingCriterion;
 
-            IModel<String> reflection = LoadableDetachableModel.of(() -> {
+            IModel<Reflection> reflection = LoadableDetachableModel.of(() -> {
                 Project project = CriteriaPanel.this.getModelObject().getProject();
-                return reflectionService.getSubmittedReflection(project, author.getObject());
+                return reflectionService.getReflection(project, author.getObject());
+            });
+            IModel<String> improvementsNeeded = reflection
+                    .as(Reflection.ImprovementsNeeded.class)
+                    .map(Reflection.ImprovementsNeeded::commentBySupervisor);
+
+            add(new MultiLineLabel("improvementsNeeded", improvementsNeeded) {
+                @Override
+                protected void onConfigure() {
+                    super.onConfigure();
+                    setVisible(!getDefaultModelObjectAsString().isBlank());
+                }
             });
 
             modal = new LargeModalWindow("modal");
             modal.setTitle("Reflection");
-            modal.setContent(id_ -> new MultiLineLabel(id_, new NullReplacementModel(reflection, "No reflection filled in.")));
+            modal.setContent(modalBodyId -> {
+                IModel<Project> projectModel = CriteriaPanel.this.getModel().map(GradingReport::getProject);
+                return new ReflectionModalBodyPanel(modalBodyId, projectModel, author);
+            });
+            this.setOutputMarkupId(true);
+            this.setOutputMarkupPlaceholderTag(true);
+            modal.onClose(target -> {
+                target.add(ReflectionFeedbackPanel.this);
+            });
             add(modal);
 
             WebMarkupContainer showReflection = new WebMarkupContainer("showReflection") {
diff --git a/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.html b/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.html
new file mode 100644
index 0000000000..7840492505
--- /dev/null
+++ b/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.html
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+<body>
+<wicket:panel>
+    <wicket:enclosure>
+        <div class="alert alert-info">
+            <h4 class="alert-heading">
+                <wicket:message key="improvements_requested">
+                    You've requested improvements to the submitted version.
+                </wicket:message>
+            </h4>
+            <wicket:container wicket:id="improvements_needed_supervisor_feedback">
+                [Supervisor feedback on needed improvements]
+            </wicket:container>
+        </div>
+    </wicket:enclosure>
+
+    <wicket:container wicket:id="reflection_text">
+        [Authors submitted reflection]
+    </wicket:container>
+
+    <button class="btn btn-outline-secondary" wicket:id="show_edit_reflection_form">
+        <wicket:message key="edit_reflection">
+            Edit reflection
+        </wicket:message>
+    </button>
+    <button class="btn btn-outline-secondary" wicket:id="show_request_improvements_form">
+        <wicket:message key="request_improvements">
+            Request improvements
+        </wicket:message>
+    </button>
+
+    <form wicket:id="request_improvements_form">
+        <hr>
+        <p>
+            <wicket:message key="request_improvements_text">
+                Please provide feedback on what improvements are needed in the submitted version.
+            </wicket:message>
+        </p>
+        <div class="mb-3">
+            <label class="form-label" wicket:for="comment">
+                <wicket:message key="comment">
+                    Comment
+                </wicket:message>
+            </label>
+            <textarea class="form-control" wicket:id="comment" rows="5"></textarea>
+        </div>
+        <button class="btn btn-primary" wicket:id="submit">
+            <wicket:message key="request_improvements">
+                Request improvements
+            </wicket:message>
+        </button>
+        <button class="btn btn-link" wicket:id="cancel">
+            <wicket:message key="cancel">
+                Cancel
+            </wicket:message>
+        </button>
+    </form>
+
+    <form wicket:id="edit_reflection_form">
+        <div class="mb-3">
+            <label class="form-label">
+                <wicket:message key="reflection">
+                    Reflection
+                </wicket:message>
+            </label>
+            <textarea class="form-control" wicket:id="reflection" rows="10"></textarea>
+        </div>
+        <button class="btn btn-primary" wicket:id="submit">
+            <wicket:message key="save">
+                Save
+            </wicket:message>
+        </button>
+        <button class="btn btn-link" wicket:id="cancel">
+            <wicket:message key="cancel">
+                Cancel
+            </wicket:message>
+        </button>
+    </form>
+</wicket:panel>
+</body>
+</html>
\ No newline at end of file
diff --git a/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.java b/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.java
new file mode 100644
index 0000000000..895e65018f
--- /dev/null
+++ b/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.java
@@ -0,0 +1,191 @@
+package se.su.dsv.scipro.grading;
+
+import jakarta.inject.Inject;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
+import org.apache.wicket.markup.html.basic.MultiLineLabel;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.form.TextArea;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import se.su.dsv.scipro.project.Project;
+import se.su.dsv.scipro.reflection.Reflection;
+import se.su.dsv.scipro.reflection.ReflectionService;
+import se.su.dsv.scipro.system.User;
+
+/**
+ * This is not meant to be a re-usable panel and is made specifically to be used
+ * as the body of the modal dialog that opens when a supervisor views the
+ * author's reflection as they're doing their final individual assessment.
+ */
+class ReflectionModalBodyPanel extends Panel {
+    @Inject
+    private ReflectionService reflectionService;
+
+    private final IModel<Project> projectModel;
+    private final IModel<User> authorModel;
+
+    private enum State { VIEWING, REQUESTING_IMPROVEMENTS, EDITING }
+
+    private State state = State.VIEWING;
+
+    ReflectionModalBodyPanel(String id, IModel<Project> projectModel, IModel<User> authorModel) {
+        super(id);
+        this.projectModel = projectModel;
+        this.authorModel = authorModel;
+
+        setOutputMarkupPlaceholderTag(true); // enable ajax refreshing of the entire body
+
+        IModel<Reflection> reflectionModel = projectModel.combineWith(authorModel, reflectionService::getReflection);
+
+        add(new MultiLineLabel("reflection_text", reflectionModel.map(this::getReflectionText)) {
+            @Override
+            protected void onConfigure() {
+                super.onConfigure();
+                setVisible(state != State.EDITING);
+            }
+        });
+
+        add(new MultiLineLabel("improvements_needed_supervisor_feedback", reflectionModel
+                .as(Reflection.ImprovementsNeeded.class)
+                .map(Reflection.ImprovementsNeeded::commentBySupervisor)) {
+            @Override
+            protected void onConfigure() {
+                super.onConfigure();
+                setVisible(!getDefaultModelObjectAsString().isBlank());
+            }
+        });
+
+        add(new RequestImprovementsForm("request_improvements_form", reflectionModel));
+        add(new SupervisorEditReflectionForm("edit_reflection_form", reflectionModel));
+
+        add(new AjaxLink<>("show_request_improvements_form", reflectionModel) {
+            @Override
+            public void onClick(AjaxRequestTarget target) {
+                ReflectionModalBodyPanel.this.state = State.REQUESTING_IMPROVEMENTS;
+                target.add(ReflectionModalBodyPanel.this);
+            }
+
+            @Override
+            protected void onConfigure() {
+                super.onConfigure();
+                Reflection reflection = getModelObject();
+                boolean canRequestImprovements = reflection instanceof Reflection.Submitted;
+                setVisible(state == State.VIEWING && canRequestImprovements && isEnabledInHierarchy());
+            }
+        });
+
+        add(new AjaxLink<>("show_edit_reflection_form", reflectionModel) {
+            @Override
+            public void onClick(AjaxRequestTarget target) {
+                ReflectionModalBodyPanel.this.state = State.EDITING;
+                target.add(ReflectionModalBodyPanel.this);
+            }
+
+            @Override
+            protected void onConfigure() {
+                super.onConfigure();
+                Reflection reflection = getModelObject();
+                boolean canEditReflection = reflection instanceof Reflection.Submitted || reflection instanceof Reflection.ImprovementsNeeded;
+                setVisible(state == State.VIEWING && canEditReflection && isEnabledInHierarchy());
+            }
+        });
+    }
+
+    private String getReflectionText(Reflection reflection) {
+        if (reflection instanceof Reflection.Submitted submitted) {
+            return submitted.reflection();
+        } else if (reflection instanceof Reflection.ImprovementsNeeded improvementsNeeded) {
+            return improvementsNeeded.oldReflection();
+        } else {
+            return getString("reflection_not_submitted");
+        }
+    }
+
+    @Override
+    protected void onDetach() {
+        this.projectModel.detach();
+        this.authorModel.detach();
+        super.onDetach();
+    }
+
+    private class RequestImprovementsForm extends Form<Reflection> {
+        public RequestImprovementsForm(String id, IModel<Reflection> reflectionModel) {
+            super(id, reflectionModel);
+
+            IModel<String> commentModel = new Model<>();
+
+            TextArea<String> comment = new TextArea<>("comment", commentModel);
+            comment.setRequired(true);
+            add(comment);
+
+            add(new AjaxSubmitLink("submit") {
+                @Override
+                protected void onSubmit(AjaxRequestTarget target) {
+                    super.onSubmit(target);
+
+                    reflectionService.requestNewReflection(
+                            projectModel.getObject(),
+                            authorModel.getObject(),
+                            commentModel.getObject());
+
+                    ReflectionModalBodyPanel.this.state = State.VIEWING;
+                    target.add(ReflectionModalBodyPanel.this);
+                }
+            });
+            add(new AjaxLink<>("cancel") {
+                @Override
+                public void onClick(AjaxRequestTarget target) {
+                    ReflectionModalBodyPanel.this.state = State.VIEWING;
+                    target.add(ReflectionModalBodyPanel.this);
+                }
+            });
+        }
+
+        @Override
+        protected void onConfigure() {
+            super.onConfigure();
+            setVisible(state == State.REQUESTING_IMPROVEMENTS && getModelObject() instanceof Reflection.Submitted);
+        }
+    }
+
+    private class SupervisorEditReflectionForm extends Form<Reflection> {
+        public SupervisorEditReflectionForm(String id, IModel<Reflection> reflectionModel) {
+            super(id, reflectionModel);
+
+            IModel<String> reflectionTextModel = new Model<>(getReflectionText(reflectionModel.getObject()));
+
+            TextArea<String> reflectionTextArea = new TextArea<>("reflection", reflectionTextModel);
+            reflectionTextArea.setRequired(true);
+            add(reflectionTextArea);
+
+            add(new AjaxSubmitLink("submit") {
+                @Override
+                protected void onSubmit(AjaxRequestTarget target) {
+                    reflectionService.submitReflection(
+                            projectModel.getObject(),
+                            authorModel.getObject(),
+                            reflectionTextModel.getObject());
+
+                    ReflectionModalBodyPanel.this.state = State.VIEWING;
+                    target.add(ReflectionModalBodyPanel.this);
+                }
+            });
+            add(new AjaxLink<>("cancel") {
+                @Override
+                public void onClick(AjaxRequestTarget target) {
+                    ReflectionModalBodyPanel.this.state = State.VIEWING;
+                    target.add(ReflectionModalBodyPanel.this);
+                }
+            });
+        }
+
+        @Override
+        protected void onConfigure() {
+            super.onConfigure();
+            setVisible(state == State.EDITING);
+        }
+    }
+}
diff --git a/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.utf8.properties b/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.utf8.properties
new file mode 100644
index 0000000000..cf818f1e92
--- /dev/null
+++ b/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.utf8.properties
@@ -0,0 +1,10 @@
+improvements_requested=You've requested improvements to the submitted version.
+request_improvements=Request improvements
+comment=Comment
+reflection_not_submitted=Reflection not submitted yet
+request_improvements_text=If the submitted reflection does not meet the minimum requirements \
+  you can request improvements from the student. The student will be notified and can submit a new reflection. \
+  Use the comment field to provide feedback to the student.
+edit_reflection=Edit reflection
+reflection=Reflection
+cancel=Cancel
diff --git a/view/src/main/java/se/su/dsv/scipro/notifications/pages/NotificationLandingPage.java b/view/src/main/java/se/su/dsv/scipro/notifications/pages/NotificationLandingPage.java
index b3b73a4bec..0fc12af49a 100644
--- a/view/src/main/java/se/su/dsv/scipro/notifications/pages/NotificationLandingPage.java
+++ b/view/src/main/java/se/su/dsv/scipro/notifications/pages/NotificationLandingPage.java
@@ -158,7 +158,7 @@ public class NotificationLandingPage extends WebPage {
                     setResponsePage(RoughDraftApprovalDecisionPage.class, reviewerParameters);
                 }
                 break;
-            case REVIEWER_GRADING_INITIAL_ASSESSMENT_DONE, REVIEWER_GRADING_REPORT_SUBMITTED:
+            case REVIEWER_GRADING_INITIAL_ASSESSMENT_DONE, REVIEWER_GRADING_REPORT_SUBMITTED, REFLECTION_IMPROVEMENTS_SUBMITTED:
                 if (project.isSupervisor(currentUser)) {
                     setResponsePage(SupervisorGradingReportPage.class, pp);
                 }
diff --git a/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.html b/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.html
index a50d6d7828..6cc7d5661d 100644
--- a/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.html
+++ b/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.html
@@ -38,6 +38,30 @@
                 <div wicket:id="current_thesis_file"></div>
             </div>
         </wicket:enclosure>
+        <wicket:enclosure child="old_reflection">
+            <div class="alert alert-info">
+                <h4 class="alert-heading">
+                    <wicket:message key="reflection_improvements_needed_heading">
+                        Reflection improvements needed
+                    </wicket:message>
+                </h4>
+                <p>
+                    <wicket:message key="reflection_improvements_needed">
+                        Your supervisor has requested that you improve and resubmit your reflection.
+                        See their comments below about what changes are necessary.
+                    </wicket:message>
+                </p>
+                <p wicket:id="supervisor_comment">
+                    [You need to reflect more on the methods you used.]
+                </p>
+            </div>
+            <h4>
+                <wicket:message key="old_reflection">
+                    Your previous reflection
+                </wicket:message>
+            </h4>
+            <p wicket:id="old_reflection"></p>
+        </wicket:enclosure>
         <div class="mb-3">
             <label class="form-label" wicket:for="reflection">
                 <wicket:message key="reflection">[Reflection]</wicket:message>
diff --git a/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.java b/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.java
index 0283f15c13..95d9fb319a 100644
--- a/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.java
@@ -24,6 +24,7 @@ import se.su.dsv.scipro.grading.PublicationMetadata;
 import se.su.dsv.scipro.grading.PublicationMetadataFormComponentPanel;
 import se.su.dsv.scipro.grading.PublicationMetadataService;
 import se.su.dsv.scipro.project.Project;
+import se.su.dsv.scipro.reflection.Reflection;
 import se.su.dsv.scipro.reflection.ReflectionService;
 import se.su.dsv.scipro.session.SciProSession;
 
@@ -45,17 +46,20 @@ public class FinalStepsPanel extends GenericPanel<Project> {
 
         add(new FencedFeedbackPanel("feedback", this));
 
-        IModel<String> reflection = LoadableDetachableModel.of(() ->
-                reflectionService.getSubmittedReflection(projectModel.getObject(), SciProSession.get().getUser()));
-        add(new MultiLineLabel("reflection", reflection) {
+        IModel<Reflection> currentReflection = LoadableDetachableModel.of(() ->
+                reflectionService.getReflection(projectModel.getObject(), SciProSession.get().getUser()));
+        IModel<String> reflectionText = currentReflection
+                .as(Reflection.Submitted.class)
+                .map(Reflection.Submitted::reflection);
+        add(new MultiLineLabel("reflection", reflectionText) {
             @Override
             protected void onConfigure() {
                 super.onConfigure();
-                setVisible(getDefaultModelObject() != null);
+                setVisible(!getDefaultModelObjectAsString().isBlank());
             }
         });
 
-        add(new FinalStepsForm("submit_reflection", projectModel));
+        add(new FinalStepsForm("submit_reflection", projectModel, currentReflection));
     }
 
     @Override
@@ -67,22 +71,49 @@ public class FinalStepsPanel extends GenericPanel<Project> {
     private class FinalStepsForm extends Form<Project> {
         private final FinalThesisUploadComponent thesisFileUpload;
         private final IModel<PublicationMetadata> publicationMetadataModel;
+        private final IModel<Reflection> currentReflection;
         private IModel<String> reflectionModel;
         private IModel<PublishingConsentService.Level> levelModel;
 
-        public FinalStepsForm(String id, IModel<Project> projectModel) {
+        public FinalStepsForm(String id, IModel<Project> projectModel, IModel<Reflection> currentReflection) {
             super(id, projectModel);
 
+            this.currentReflection = currentReflection;
+
+            IModel<Reflection.ImprovementsNeeded> improvementsNeeded = this.currentReflection.as(Reflection.ImprovementsNeeded.class);
+
+            IModel<String> oldReflection = improvementsNeeded.map(Reflection.ImprovementsNeeded::oldReflection);
+            add(new MultiLineLabel("old_reflection", oldReflection) {
+                @Override
+                protected void onConfigure() {
+                    super.onConfigure();
+                    setVisibilityAllowed(!getDefaultModelObjectAsString().isBlank());
+                }
+            });
+
+            add(new MultiLineLabel("supervisor_comment", improvementsNeeded.map(Reflection.ImprovementsNeeded::commentBySupervisor)) {
+                @Override
+                protected void onConfigure() {
+                    super.onConfigure();
+                    setVisibilityAllowed(!getDefaultModelObjectAsString().isBlank());
+                }
+            });
 
             reflectionModel = new Model<>();
-            TextArea<String> reflectionTextArea = new TextArea<>("reflection", reflectionModel);
+            TextArea<String> reflectionTextArea = new TextArea<>("reflection", reflectionModel) {
+                @Override
+                protected void onConfigure() {
+                    super.onConfigure();
+                    setVisible(FinalStepsForm.this.currentReflection.getObject().isSubmittable());
+                }
+            };
             reflectionTextArea.setRequired(true);
             add(reflectionTextArea);
 
             IModel<PublishingConsentService.PublishingConsent> publishingConsent = LoadableDetachableModel.of(() ->
                     publishingConsentService.getPublishingConsent(getModelObject(), SciProSession.get().getUser()));
 
-            levelModel = new Model<>();
+            levelModel = new Model<>(publishingConsent.getObject().selected());
             FormComponent<PublishingConsentService.Level> publishingConsentLevel = new BootstrapRadioChoice<>(
                     "publishingConsentLevel",
                     levelModel,
@@ -111,7 +142,13 @@ public class FinalStepsPanel extends GenericPanel<Project> {
             currentThesisFile.add(new OppositeVisibility(thesisFileUpload));
             add(currentThesisFile);
             publicationMetadataModel = LoadableDetachableModel.of(() -> publicationMetadataService.getByProject(getModelObject()));
-            WebMarkupContainer publicationMetadata = new WebMarkupContainer("publication_metadata");
+            WebMarkupContainer publicationMetadata = new WebMarkupContainer("publication_metadata") {
+                @Override
+                protected void onConfigure() {
+                    super.onConfigure();
+                    setEnabled(finalThesisService.isUploadAllowed(FinalStepsPanel.FinalStepsForm.this.getModelObject()));
+                }
+            };
             add(publicationMetadata);
             publicationMetadata.add(new PublicationMetadataFormComponentPanel("publication_metadata_components", publicationMetadataModel));
         }
@@ -119,7 +156,7 @@ public class FinalStepsPanel extends GenericPanel<Project> {
         @Override
         protected void onConfigure() {
             super.onConfigure();
-            setVisibilityAllowed(reflectionService.hasToFillInReflection(getModelObject(), SciProSession.get().getUser()));
+            setVisibilityAllowed(currentReflection.getObject().isSubmittable());
         }
 
         @Override
@@ -131,6 +168,7 @@ public class FinalStepsPanel extends GenericPanel<Project> {
                         new WicketProjectFileUpload(finalThesisUpload.fileUpload(), FinalStepsPanel.this.getModelObject()),
                         finalThesisUpload.englishTitle(),
                         finalThesisUpload.swedishTitle());
+                success(getString("final_thesis_uploaded"));
             }
             reflectionService.submitReflection(getModelObject(), SciProSession.get().getUser(), reflectionModel.getObject());
             if (levelModel.getObject() != null) {
diff --git a/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.utf8.properties b/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.utf8.properties
index a0f79eb71a..f21ad3bd37 100644
--- a/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.utf8.properties
+++ b/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.utf8.properties
@@ -9,3 +9,8 @@ current_final_thesis=Final thesis
 publication_metadata_why=Please provide the following metadata.
 englishTitle=English title
 swedishTitle=Swedish title
+reflection_improvements_needed_heading=Reflection improvements needed
+reflection_improvements_needed=Your supervisor has requested that you improve and resubmit your reflection. \
+See their comments below about what changes are necessary.
+old_reflection=Your previous reflection
+final_thesis_uploaded=Final thesis uploaded
diff --git a/view/src/main/java/se/su/dsv/scipro/wicket-package.utf8.properties b/view/src/main/java/se/su/dsv/scipro/wicket-package.utf8.properties
index 74aa56c867..97ea5d57c3 100644
--- a/view/src/main/java/se/su/dsv/scipro/wicket-package.utf8.properties
+++ b/view/src/main/java/se/su/dsv/scipro/wicket-package.utf8.properties
@@ -65,6 +65,8 @@ ProjectEvent.FIRST_MEETING = First meeting created. (with date, time, place/room
 ProjectEvent.OPPOSITION_FAILED = An author fails their opposition.
 ProjectEvent.PARTICIPATION_APPROVED = An author's active participation is approved.
 ProjectEvent.PARTICIPATION_FAILED = An author fails their active participation.
+ProjectEvent.REFLECTION_IMPROVEMENTS_REQUESTED = Reflection improvements requested.
+ProjectEvent.REFLECTION_IMPROVEMENTS_SUBMITTED = Reflection improvements submitted.
 
 ProjectForumEvent.NEW_FORUM_POST = Forum thread created.
 ProjectForumEvent.NEW_FORUM_POST_COMMENT = Comment posted in forum thread.
diff --git a/view/src/test/java/se/su/dsv/scipro/SciProTest.java b/view/src/test/java/se/su/dsv/scipro/SciProTest.java
index e712c36790..2b469c39ec 100755
--- a/view/src/test/java/se/su/dsv/scipro/SciProTest.java
+++ b/view/src/test/java/se/su/dsv/scipro/SciProTest.java
@@ -139,6 +139,7 @@ import java.util.*;
 import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.lenient;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 @ExtendWith(MockitoExtension.class)
 public abstract class SciProTest {
@@ -390,6 +391,8 @@ public abstract class SciProTest {
                     publicationMetadata.setProject(answer.getArgument(0));
                     return publicationMetadata;
                 });
+        lenient().when(publishingConsentService.getPublishingConsent(any(), any()))
+                .thenReturn(new PublishingConsentService.PublishingConsent(null, List.of()));
     }
 
     @BeforeEach
diff --git a/war/src/main/java/se/su/dsv/scipro/war/WicketConfiguration.java b/war/src/main/java/se/su/dsv/scipro/war/WicketConfiguration.java
index f31d390c16..bb255d4915 100644
--- a/war/src/main/java/se/su/dsv/scipro/war/WicketConfiguration.java
+++ b/war/src/main/java/se/su/dsv/scipro/war/WicketConfiguration.java
@@ -10,6 +10,7 @@ import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import se.su.dsv.scipro.SciProApplication;
 import se.su.dsv.scipro.crosscutting.ForwardPhase2Feedback;
+import se.su.dsv.scipro.crosscutting.NotifyFailedReflection;
 import se.su.dsv.scipro.crosscutting.ReviewerAssignedNotifications;
 import se.su.dsv.scipro.crosscutting.ReviewerSupportMailer;
 import se.su.dsv.scipro.crosscutting.ReviewingNotifications;
@@ -87,4 +88,13 @@ public class WicketConfiguration {
         return new ReviewerAssignedNotifications(roughDraftApprovalService,
                 finalSeminarApprovalService, notificationController, eventBus);
     }
+
+    // Not sure why this dependency lives in the view module
+    @Bean
+    public NotifyFailedReflection notifyFailedReflection(
+            EventBus eventBus,
+            NotificationController notificationController)
+    {
+        return new NotifyFailedReflection(notificationController, eventBus);
+    }
 }