diff --git a/controllers/solutions.php b/controllers/solutions.php
index 9e03ced2474b16bfe5e69e3d9156e111f230f6ed..fa943dc3c766a0077229cd36f4a06fcdfbea5ae1 100644
--- a/controllers/solutions.php
+++ b/controllers/solutions.php
@@ -303,6 +303,16 @@ class SolutionsController extends StudipController
             $solvers[$solver_id]['extra_info'] = $extra_info;
         }
 
+        $confirm = [];
+
+        if (!$released) {
+            $num_corrected = count($assignment->assignment_attempts->filter(function($a) { return $a->options['corrected']; }));
+
+            if ($num_corrected > 0 && $num_corrected < count($assignment->assignment_attempts)) {
+                $confirm = ['data-confirm' => _vips('Es sind noch nicht alle Ergebnisse bestätigt. Wollen Sie trotzdem die Ergebnisse freigeben?')];
+            }
+        }
+
         $this->assignment                    = $assignment;
         $this->assignment_id                 = $assignment_id;
         $this->view                          = $view;
@@ -420,16 +430,16 @@ class SolutionsController extends StudipController
                 $released == 0);
             $widget->addRadioButton(_vips('vergebene Punkte'),
                 $this->link_for('solutions/change_released', ['assignment_id' => $assignment_id, 'released' => 1]),
-                $released == 1);
+                $released == 1, $confirm);
             $widget->addRadioButton(_vips('Punkte und Kommentare'),
                 $this->link_for('solutions/change_released', ['assignment_id' => $assignment_id, 'released' => 2]),
-                $released == 2);
+                $released == 2, $confirm);
             $widget->addRadioButton(_vips('… zusätzlich Aufgaben und Korrektur'),
                 $this->link_for('solutions/change_released', ['assignment_id' => $assignment_id, 'released' => 3]),
-                $released == 3);
+                $released == 3, $confirm);
             $widget->addRadioButton(_vips('… zusätzlich Musterlösungen'),
                 $this->link_for('solutions/change_released', ['assignment_id' => $assignment_id, 'released' => 4]),
-                $released == 4);
+                $released == 4, $confirm);
             Sidebar::get()->addWidget($widget);
 
             $widget = new SidebarWidget();
@@ -1147,6 +1157,97 @@ class SolutionsController extends StudipController
         $this->redirect($this->url_for('solutions/assignment_solutions', compact('assignment_id', 'view')));
     }
 
+    /**
+     * Add assignment level feedback to an assignment attempt.
+     */
+    public function edit_feedback_dialog_action()
+    {
+        $assignment_id = Request::int('assignment_id');
+        $assignment    = VipsAssignment::find($assignment_id);
+        $user_ids      = Request::optionArray('user_ids');
+        $view          = Request::option('view');
+
+        vips_require_edit_permission($assignment);
+
+        $this->assignment = $assignment;
+        $this->user_ids   = $user_ids;
+        $this->view       = $view;
+        $this->feedback   = null;
+        $this->corrected  = null;
+
+        foreach ($user_ids as $user_id) {
+            $assignment_attempt = $assignment->getAssignmentAttempt($user_id);
+            $feedback = $assignment->getUserFeedback($user_id) ?? '';
+            $corrected = $assignment_attempt->options['corrected'] ?? 0;
+
+            if (!isset($this->feedback) || $this->feedback === $feedback) {
+                $this->feedback = $feedback;
+            } else {
+                $this->feedback = '';
+            }
+
+            if (!isset($this->corrected) || $this->corrected === $corrected) {
+                $this->corrected = $corrected;
+            } else {
+                $this->corrected = 0;
+            }
+        }
+    }
+
+    /**
+     * Store feedback and status for an assignment attempt.
+     */
+    public function edit_feedback_action()
+    {
+        CSRFProtection::verifyUnsafeRequest();
+
+        $assignment_id = Request::int('assignment_id');
+        $assignment    = VipsAssignment::find($assignment_id);
+        $user_ids      = Request::optionArray('user_ids');
+        $view          = Request::option('view');
+
+        $feedback      = trim(Request::get('feedback'));
+        $feedback      = Studip\Markup::purifyHtml($feedback);
+        $corrected     = Request::int('corrected');
+
+        vips_require_edit_permission($assignment);
+
+        foreach ($user_ids as $user_id) {
+            $assignment_attempt = $assignment->getAssignmentAttempt($user_id);
+
+            if ($assignment_attempt) {
+                $options = $assignment_attempt->options;
+
+                unset($options['feedback']);
+
+                if ($feedback !== '') {
+                    $options['feedback'] = $feedback;
+                }
+
+                if (!$corrected) {
+                    unset($options['corrected']);
+                    unset($options['corrector_id']);
+                    unset($options['correction_time']);
+                } else if (!$options['corrected']) {
+                    $options['corrected'] = $corrected;
+                    $options['corrector_id'] = $GLOBALS['user']->id;
+                    $options['correction_time'] = time();
+                }
+
+                $assignment_attempt->options = $options;
+                $assignment_attempt->store();
+            }
+        }
+
+        if ($feedback === '' && !$corrected) {
+            PageLayout::postSuccess(_vips('Der Kommentar zur Bewertung wurde entfernt.'));
+        } else {
+            PageLayout::postSuccess(_vips('Der Kommentar zur Bewertung wurde gespeichert.'));
+        }
+
+        $this->redirect($this->url_for('solutions/assignment_solutions', compact('assignment_id', 'view')));
+    }
+
     /**
      * Write a message to selected members for an assignment.
      */
@@ -1376,6 +1477,7 @@ class SolutionsController extends StudipController
         $this->user_id = $GLOBALS['user']->id;
         $this->released = $assignment->releaseStatus($this->user_id);
         $this->feedback = $assignment->getUserFeedback($this->user_id);
+        $this->assignment_attempt = $assignment->getAssignmentAttempt($this->user_id);
 
         // Security check -- is assignment really accessible for students?
         if ($this->released == 0) {
@@ -2228,7 +2330,8 @@ function get_solutions($assignment, $view)
         $solvers[$user_id] = [
             'type'      => 'single',
             'id'        => $user_id,
-            'user_id'   => $user_id
+            'user_id'   => $user_id,
+            'feedback'  => $attempt->options['feedback']
         ];
     }
 
diff --git a/lib/VipsAssignment.php b/lib/VipsAssignment.php
index a91e17e0b76a1303e0ae754ffd4131ef4bc3f692..823946e29c6072c65c1130d18816ceaee171cc23 100644
--- a/lib/VipsAssignment.php
+++ b/lib/VipsAssignment.php
@@ -1133,6 +1133,12 @@ class VipsAssignment extends SimpleORMap
      */
     public function getUserFeedback($user_id)
     {
+        $assignment_attempt = $this->getAssignmentAttempt($user_id);
+
+        if ($assignment_attempt && isset($assignment_attempt->options['feedback'])) {
+            return $assignment_attempt->options['feedback'];
+        }
+
         if (isset($this->options['feedback'])) {
             $user_points = $this->getUserPoints($user_id);
             $max_points = $this->test->getTotalPoints();
diff --git a/views/sheets/print_assignment.php b/views/sheets/print_assignment.php
index 4fa307a79b1b6a2703eb5767cc57ea453df62aa7..e489e463b8aa99961d47e3a9718e1aaaf51e98be 100644
--- a/views/sheets/print_assignment.php
+++ b/views/sheets/print_assignment.php
@@ -69,6 +69,7 @@
         <? $max_points = $assignment->test->getTotalPoints(); ?>
         <? $reached_points = $assignment->getUserPoints($user_id); ?>
         <? $feedback = $assignment->getUserFeedback($user_id); ?>
+        <? $assignment_attempt = $assignment->getAssignmentAttempt($user_id); ?>
         <div class="exercise">
             <h2>
                 <?= _vips('Gesamtpunktzahl') ?>
@@ -89,6 +90,10 @@
 
                 <?= formatReady($feedback) ?>
             <? endif ?>
+
+            <? if ($assignment_attempt->options['corrected']): ?>
+                <?= sprintf(_vips('Bewertung wurde am %s von %s bestätigt.'), date('d.m.Y', $assignment_attempt->options['correction_time']), htmlReady(get_fullname($assignment_attempt->options['corrector_id']))) ?>
+            <? endif ?>
         </div>
         <? setlocale(LC_NUMERIC, 'C') ?>
     <? endif ?>
diff --git a/views/solutions/assignment_solutions.php b/views/solutions/assignment_solutions.php
index beea89e0da97930dad118cf83b4ff6610f31b4b3..46bb89f90adb22e24d521bf07787d87da6228fd0 100644
--- a/views/solutions/assignment_solutions.php
+++ b/views/solutions/assignment_solutions.php
@@ -115,6 +115,9 @@
                             <?= Icon::create('arr_1right', 'clickable', ['class' => 'solution-open', 'title' => _vips('Aufgaben anzeigen')]) ?>
                             <?= Icon::create('arr_1down', 'clickable', ['class' => 'solution-close', 'title' => _vips('Aufgaben verstecken')]) ?>
                             <?= htmlReady($solver['name']) ?>
+                            <? if ($solver['feedback']): ?>
+                                <?= tooltipIcon(kill_format($solver['feedback'])) ?>
+                            <? endif ?>
                         </a>
 
                         <? if ($solver['type'] == 'single') : ?>
@@ -199,6 +202,9 @@
                             <? $menu->addLink($controller->url_for('solutions/show_assignment_log', ['assignment_id' => $assignment_id, 'solver_id' => $solver['user_id']]),
                                    _vips('Abgabeprotokoll anzeigen'), Icon::create('log'), ['data-dialog' => 'size=auto']
                                ) ?>
+                            <? $menu->addLink($controller->url_for('solutions/edit_feedback_dialog', ['assignment_id' => $assignment_id, 'user_ids[]' => $solver['user_id'], 'view' => $view]),
+                                   _vips('Kommentar zur Bewertung'), Icon::create('feedback'), ['data-dialog' => 'size=800x440']
+                               ) ?>
                         <? endif ?>
                         <? if ($uploaded_files > 0): ?>
                             <? $menu->addLink($controller->url_for('solutions/download_uploads', ['assignment_id' => $assignment_id, 'solver_id' => $solver['user_id']]),
@@ -298,6 +304,12 @@
                                 'formmethod' => 'post',
                                 'formtarget' => '_blank'
                             ]) ?>
+                        <?= Studip\Button::create(_vips('Kommentar zur Bewertung'), 'feedback', [
+                                'class' => 'batch_action',
+                                'formaction' => $controller->url_for('solutions/edit_feedback_dialog'),
+                                'formmethod' => 'post',
+                                'data-dialog' => 'size=800x440'
+                            ]) ?>
                         <?= Studip\Button::create(_vips('Nachricht schreiben'), 'message', [
                                 'class' => 'batch_action',
                                 'formaction' => $controller->url_for('solutions/write_message'),
diff --git a/views/solutions/edit_feedback_dialog.php b/views/solutions/edit_feedback_dialog.php
new file mode 100644
index 0000000000000000000000000000000000000000..e54cb3a09e34e599d91e0c83099712e86306d845
--- /dev/null
+++ b/views/solutions/edit_feedback_dialog.php
@@ -0,0 +1,22 @@
+<form class="default" action="<?= $controller->link_for('solutions/edit_feedback') ?>" method="POST">
+    <?= CSRFProtection::tokenTag() ?>
+    <input type="hidden" name="assignment_id" value="<?= $assignment->id ?>">
+    <? foreach ($user_ids as $user_id): ?>
+        <input type="hidden" name="user_ids[]" value="<?= $user_id ?>">
+    <? endforeach ?>
+    <input type="hidden" name="view" value="<?= $view ?>">
+
+    <label>
+        <?= _vips('Kommentar zur Bewertung') ?>
+        <textarea name="feedback" class="size-l wysiwyg" data-editor="toolbar=small"><?= wysiwygReady($feedback) ?></textarea>
+    </label>
+
+    <label>
+        <input type="checkbox" name="corrected" value="1" <?= $corrected ? 'checked' : '' ?>>
+        <?= _vips('Bestätigungsvermerk hinzufügen') ?>
+    </label>
+
+    <footer data-dialog-button>
+        <?= Studip\Button::createAccept(_vips('Speichern'), 'save') ?>
+    </footer>
+</form>
diff --git a/views/solutions/student_assignment_solutions.php b/views/solutions/student_assignment_solutions.php
index fe1ece0f973206c94f95382c9785868251f0fd1d..a746e34f1d499d14110ab25efadce24200ac6517 100644
--- a/views/solutions/student_assignment_solutions.php
+++ b/views/solutions/student_assignment_solutions.php
@@ -113,4 +113,8 @@
     </div>
 <? endif ?>
 
+<? if ($assignment_attempt->options['corrected']): ?>
+    <?= sprintf(_vips('Bewertung wurde am %s von %s bestätigt.'), date('d.m.Y', $assignment_attempt->options['correction_time']), htmlReady(get_fullname($assignment_attempt->options['corrector_id']))) ?>
+<? endif ?>
+
 <? setlocale(LC_NUMERIC, 'C') ?>