diff --git a/lib/classes/FeedbackRange.interface.php b/lib/classes/FeedbackRange.interface.php
index f5eaaeff743f622619105796e93d2ad858eadb61..863c197ba64f4424e8be500144c7ac74948b851c 100644
--- a/lib/classes/FeedbackRange.interface.php
+++ b/lib/classes/FeedbackRange.interface.php
@@ -11,6 +11,13 @@
 
 interface FeedbackRange
 {
+    /**
+     * Returns the ID of this range.
+     *
+     * @return string|integer The ID of the range.
+     */
+    public function getId();
+
     /**
      * Returns a human-friendly representation of the FeedbackRange object instance's name.
      *
diff --git a/lib/classes/JsonApi/RouteMap.php b/lib/classes/JsonApi/RouteMap.php
index 2eb33a815e2869bf776046c189f7cc93f0b47e91..0177db0cf373262c4ca7547fd73fdb165f27bd78 100644
--- a/lib/classes/JsonApi/RouteMap.php
+++ b/lib/classes/JsonApi/RouteMap.php
@@ -239,12 +239,20 @@ class RouteMap
     private function addAuthenticatedFeedbackRoutes(RouteCollectorProxy $group): void
     {
         $group->get('/feedback-elements/{id}', Routes\Feedback\FeedbackElementsShow::class);
-        $group->get('/feedback-elements/{id}/entries', Routes\Feedback\FeedbackEntriesIndex::class);
         $group->get('/courses/{id}/feedback-elements', Routes\Feedback\FeedbackElementsByCourseIndex::class);
         $group->get('/file-refs/{id}/feedback-elements', Routes\Feedback\FeedbackElementsByFileRefIndex::class);
         $group->get('/folders/{id}/feedback-elements', Routes\Feedback\FeedbackElementsByFolderIndex::class);
 
+        $group->post('/feedback-elements', Routes\Feedback\FeedbackElementsCreate::class);
+        $group->patch('/feedback-elements/{id}', Routes\Feedback\FeedbackElementsUpdate::class);
+        $group->delete('/feedback-elements/{id}', Routes\Feedback\FeedbackElementsDelete::class);
+
+        $group->get('/feedback-elements/{id}/entries', Routes\Feedback\FeedbackEntriesIndex::class);
+        $group->post('/feedback-entries', Routes\Feedback\FeedbackEntriesCreate::class);
+
         $group->get('/feedback-entries/{id}', Routes\Feedback\FeedbackEntriesShow::class);
+        $group->patch('/feedback-entries/{id}', Routes\Feedback\FeedbackEntriesUpdate::class);
+        $group->delete('/feedback-entries/{id}', Routes\Feedback\FeedbackEntriesDelete::class);
     }
 
     private function addAuthenticatedInstitutesRoutes(RouteCollectorProxy $group): void
@@ -299,7 +307,7 @@ class RouteMap
         $group->get('/tree-node/{id}', Routes\Tree\TreeShow::class);
 
         $group->get('/tree-node/{id}/children', Routes\Tree\ChildrenOfTreeNode::class);
-        $group->get('/tree-node/{id}/courseinfo', Routes\Tree\CourseInfoOfTreeNode::class);
+        $group->get('/tree-node/{id}/courseinfo', Routes\Tree\CourseinfoOfTreeNode::class);
         $group->get('/tree-node/{id}/courses', Routes\Tree\CoursesOfTreeNode::class);
         $group->get('/tree-node/course/pathinfo/{classname}/{id}', Routes\Tree\PathinfoOfTreeNodeCourse::class);
         $group->get('/tree-node/course/details/{id}', Routes\Tree\DetailsOfTreeNodeCourse::class);
diff --git a/lib/classes/JsonApi/Routes/Feedback/Authority.php b/lib/classes/JsonApi/Routes/Feedback/Authority.php
index 44397817fa063b867b91ae19a4657dce56b3a28b..683f1ae96d653659b6a2e623f83b0def30bf4432 100644
--- a/lib/classes/JsonApi/Routes/Feedback/Authority.php
+++ b/lib/classes/JsonApi/Routes/Feedback/Authority.php
@@ -2,45 +2,109 @@
 
 namespace JsonApi\Routes\Feedback;
 
+use Feedback;
+use FeedbackElement;
+use FeedbackEntry;
+use FeedbackRange;
+use SimpleORMap;
 use User;
 
+/**
+ * @SuppressWarnings(PHPMD.StaticAccess)
+ * @SuppressWarnings(PHPMD.TooManyPublicMethods)
+ */
 class Authority
 {
-    public static function canShowFeedbackElement(User $user, \FeedbackElement $resource)
+    public static function canShowFeedbackElement(User $user, FeedbackElement $resource): bool
     {
-        return \Feedback::hasRangeAccess($resource->range_id, $resource->range_type, $user->id);
+        return Feedback::hasRangeAccess($resource->range_id, $resource->range_type, $user->getId());
     }
 
-    public static function canIndexFeedbackEntries(User $user, \FeedbackElement $resource)
+    public static function canIndexFeedbackEntries(User $user, FeedbackElement $resource): bool
     {
         return self::canShowFeedbackElement($user, $resource);
     }
 
-    public static function canSeeResultsOfFeedbackElement(User $user, \FeedbackElement $resource)
+    public static function canSeeResultsOfFeedbackElement(User $user, FeedbackElement $resource): bool
     {
         return self::canIndexFeedbackEntries($user, $resource) &&
-            ($resource['results_visible'] || \Feedback::hasAdminPerm($resource['course_id'], $user->id));
+            ($resource['results_visible'] || \Feedback::hasAdminPerm($resource['course_id'], $user->getId()));
     }
 
-    public static function canIndexFeedbackElementsOfCourse(User $user, \Course $course)
+    public static function canIndexFeedbackElementsOfCourse(User $user, \Course $course): bool
     {
-        return \Feedback::hasRangeAccess($course->id, \Course::class, $user->id);
+        return \Feedback::hasRangeAccess($course->getId(), \Course::class, $user->getId());
     }
 
-    public static function canIndexFeedbackElementsOfFileRef(User $user, \FileRef $fileRef)
+    public static function canIndexFeedbackElementsOfFileRef(User $user, \FileRef $fileRef): bool
     {
-        return \Feedback::hasRangeAccess($fileRef->id, \FileRef::class, $user->id);
+        return \Feedback::hasRangeAccess($fileRef->getId(), \FileRef::class, $user->getId());
     }
 
-    public static function canIndexFeedbackElementsOfFolder(User $user, \Folder $folder)
+    public static function canIndexFeedbackElementsOfFolder(User $user, \Folder $folder): bool
     {
-        return \Feedback::hasRangeAccess($folder->id, \Folder::class, $user->id);
+        return \Feedback::hasRangeAccess($folder->getId(), \Folder::class, $user->getId());
     }
 
-    public static function canShowFeedbackEntry(User $user, \FeedbackEntry $resource)
+    public static function canShowFeedbackEntry(User $user, \FeedbackEntry $resource): bool
     {
         $feedbackElement = $resource->feedback;
 
         return self::canShowFeedbackElement($user, $feedbackElement);
     }
+
+    /**
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    public static function canCreateFeedbackEntry(User $user, FeedbackElement $element): bool
+    {
+        if (!$element->isFeedbackable()) {
+            return false;
+        }
+
+        // TODO: Wann darf ich Feedback Entries schreiben
+        return true;
+    }
+
+    /**
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    public static function canUpdateFeedbackEntry(User $user, FeedbackEntry $entry): bool
+    {
+        if (!$entry->isEditable()) {
+            return false;
+        }
+
+        // TODO: Wann darf ich Feedback Entries bearbeiten
+        return true;
+    }
+
+    public static function canDeleteFeedbackEntry(User $user, FeedbackEntry $entry): bool
+    {
+        return self::canUpdateFeedbackEntry($user, $entry);
+    }
+
+    /**
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    public static function canCreateFeedbackElement(User $user, FeedbackRange $range): bool
+    {
+        // TODO: Wann darf ich Feedback Elemente anhängen
+        // bisher https://gitlab.studip.de/studip/studip/-/blob/main/lib/classes/Feedback.class.php#L76
+        return true;
+    }
+
+    /**
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    public static function canUpdateFeedbackElement(User $user, FeedbackElement $element): bool
+    {
+        // TODO: Wann darf ich Feedback Elemente ändern?
+        return true;
+    }
+
+    public static function canDeleteFeedbackElement(User $user, FeedbackElement $element): bool
+    {
+        return self::canUpdateFeedbackElement($user, $element);
+    }
 }
diff --git a/lib/classes/JsonApi/Routes/Feedback/FeedbackElementsCreate.php b/lib/classes/JsonApi/Routes/Feedback/FeedbackElementsCreate.php
new file mode 100644
index 0000000000000000000000000000000000000000..85dd4bea810cbc852090b0d826ac791f4099a17c
--- /dev/null
+++ b/lib/classes/JsonApi/Routes/Feedback/FeedbackElementsCreate.php
@@ -0,0 +1,116 @@
+<?php
+
+namespace JsonApi\Routes\Feedback;
+
+use FeedbackElement;
+use FeedbackRange;
+use User;
+use JsonApi\Errors\AuthorizationFailedException;
+use JsonApi\JsonApiController;
+use JsonApi\Routes\ValidationTrait;
+use JsonApi\Schemas\FeedbackElement as FeedbackElementSchema;
+use Psr\Http\Message\ResponseInterface as Response;
+use Psr\Http\Message\ServerRequestInterface as Request;
+
+/**
+ * Create a FeedbackElement.
+ *
+ * @SuppressWarnings(PHPMD.StaticAccess)
+ */
+class FeedbackElementsCreate extends JsonApiController
+{
+    use RangeTypeAware;
+    use ValidationTrait;
+
+    /**
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     *
+     * @param array $args
+     *
+     * @return Response
+     */
+    public function __invoke(Request $request, Response $response, $args)
+    {
+        $this->preparePossibleRangeTypes();
+
+        $json = $this->validate($request);
+        $range = $this->getRangeFromJson($json);
+        $user = $this->getUser($request);
+
+        if (!Authority::canCreateFeedbackElement($user, $range)) {
+            throw new AuthorizationFailedException();
+        }
+
+        $feedbackElement = $this->create($user, $json);
+
+        return $this->getCreatedResponse($feedbackElement);
+    }
+
+    /**
+     * @SuppressWarnings(PHPMD.UnusedFormalParameters)
+     *
+     * @param array $json
+     * @param mixed $data
+     *
+     * @return string|void
+     */
+    protected function validateResourceDocument($json, $data)
+    {
+        if (!self::arrayHas($json, 'data')) {
+            return 'Missing `data` member at document´s top level.';
+        }
+        if (FeedbackElementSchema::TYPE !== self::arrayGet($json, 'data.type')) {
+            return 'Invalid `type` of document´s `data`.';
+        }
+        if (self::arrayHas($json, 'data.id')) {
+            return 'New document must not have an `id`.';
+        }
+
+        $required = ['question', 'description', 'mode', 'results-visible', 'is-commentable'];
+        foreach ($required as $attribute) {
+            if (!self::arrayHas($json, 'data.attributes.' . $attribute)) {
+                return 'Missing `' . $attribute . '` attribute.';
+            }
+        }
+
+        if (!self::arrayHas($json, 'data.relationships.range')) {
+            return 'Missing `range` relationship.';
+        }
+        if (!$this->getRangeFromJson($json)) {
+            return 'Invalid `range` relationship.';
+        }
+    }
+
+    private function getRangeFromJson(array $json): ?FeedbackRange
+    {
+        $rangeType = self::arrayGet($json, 'data.relationships.range.data.type');
+        $rangeId = self::arrayGet($json, 'data.relationships.range.data.id');
+
+        if (!isset($this->possibleRangeTypes[$rangeType])) {
+            return null;
+        }
+        $rangeClass = $this->possibleRangeTypes[$rangeType];
+
+        return $rangeClass::find($rangeId);
+    }
+
+    private function create(User $user, array $json): FeedbackElement
+    {
+        $range = $this->getRangeFromJson($json);
+        $feedback = \FeedbackElement::build([
+            'range_id' => $range->getId(),
+            'range_type' => get_class($range),
+            'user_id' => $user->getId(),
+            'question' => self::arrayGet($json, 'data.attributes.question'),
+            'description' => self::arrayGet($json, 'data.attributes.description'),
+            'mode' => self::arrayGet($json, 'data.attributes.mode'),
+            'results_visible' => (int) self::arrayGet($json, 'data.attributes.results-visible'),
+            'commentable' => (int) self::arrayGet($json, 'data.attributes.is-commentable'),
+            // TODO:
+            'course_id' => $range->getRangeCourseId(),
+        ]);
+        $feedback->store();
+
+        return $feedback;
+    }
+}
diff --git a/lib/classes/JsonApi/Routes/Feedback/FeedbackElementsDelete.php b/lib/classes/JsonApi/Routes/Feedback/FeedbackElementsDelete.php
new file mode 100644
index 0000000000000000000000000000000000000000..874a172e7082cdaa337888e57126288409720081
--- /dev/null
+++ b/lib/classes/JsonApi/Routes/Feedback/FeedbackElementsDelete.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace JsonApi\Routes\Feedback;
+
+use Psr\Http\Message\ServerRequestInterface as Request;
+use Psr\Http\Message\ResponseInterface as Response;
+use JsonApi\Errors\AuthorizationFailedException;
+use JsonApi\Errors\RecordNotFoundException;
+use JsonApi\JsonApiController;
+
+/**
+ * Deletes a feedback element.
+ *
+ * @SuppressWarnings(PHPMD.StaticAccess)
+ */
+class FeedbackElementsDelete extends JsonApiController
+{
+    /**
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     *
+     * @param array $args
+     *
+     * @return Response
+     */
+    public function __invoke(Request $request, Response $response, $args)
+    {
+        $resource = \FeedbackElement::find($args['id']);
+        if (!$resource) {
+            throw new RecordNotFoundException();
+        }
+
+        if (!Authority::canDeleteFeedbackElement($this->getUser($request), $resource)) {
+            throw new AuthorizationFailedException();
+        }
+        $resource->delete();
+
+        return $this->getCodeResponse(204);
+    }
+}
diff --git a/lib/classes/JsonApi/Routes/Feedback/FeedbackElementsShow.php b/lib/classes/JsonApi/Routes/Feedback/FeedbackElementsShow.php
index 5ecc5932c83f5548d14aabea816251d06e253831..849e58a7ea9f2beed3627b81d3a7e240ed241345 100644
--- a/lib/classes/JsonApi/Routes/Feedback/FeedbackElementsShow.php
+++ b/lib/classes/JsonApi/Routes/Feedback/FeedbackElementsShow.php
@@ -7,20 +7,33 @@ use Psr\Http\Message\ResponseInterface as Response;
 use JsonApi\Errors\AuthorizationFailedException;
 use JsonApi\Errors\RecordNotFoundException;
 use JsonApi\JsonApiController;
+use JsonApi\Schemas\FeedbackElement as FeedbackElementSchema;
 
 /**
  * Displays a certain feedback element.
+ *
+ * @SuppressWarnings(PHPMD.StaticAccess)
  */
 class FeedbackElementsShow extends JsonApiController
 {
-    protected $allowedIncludePaths = ['author', 'course', 'entries', 'range'];
+    protected $allowedIncludePaths = [
+        FeedbackElementSchema::REL_AUTHOR,
+        FeedbackElementSchema::REL_COURSE,
+        FeedbackElementSchema::REL_ENTRIES,
+        FeedbackElementSchema::REL_RANGE,
+    ];
 
     /**
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     *
+     * @param array $args
+     *
+     * @return Response
      */
     public function __invoke(Request $request, Response $response, $args)
     {
-        if (!$resource = \FeedbackElement::find($args['id'])) {
+        $resource = \FeedbackElement::find($args['id']);
+        if (!$resource) {
             throw new RecordNotFoundException();
         }
 
diff --git a/lib/classes/JsonApi/Routes/Feedback/FeedbackElementsUpdate.php b/lib/classes/JsonApi/Routes/Feedback/FeedbackElementsUpdate.php
new file mode 100644
index 0000000000000000000000000000000000000000..4a9460b63920b0e2cb3d922fbc3b03d1e1a36875
--- /dev/null
+++ b/lib/classes/JsonApi/Routes/Feedback/FeedbackElementsUpdate.php
@@ -0,0 +1,100 @@
+<?php
+
+namespace JsonApi\Routes\Feedback;
+
+use FeedbackElement;
+use FeedbackRange;
+use User;
+use JsonApi\Errors\AuthorizationFailedException;
+use JsonApi\Errors\RecordNotFoundException;
+use JsonApi\JsonApiController;
+use JsonApi\Routes\ValidationTrait;
+use JsonApi\Schemas\FeedbackElement as FeedbackElementSchema;
+use Psr\Http\Message\ResponseInterface as Response;
+use Psr\Http\Message\ServerRequestInterface as Request;
+
+/**
+ * Update a FeedbackElement.
+ *
+ * @SuppressWarnings(PHPMD.StaticAccess)
+ */
+class FeedbackElementsUpdate extends JsonApiController
+{
+    use RangeTypeAware;
+    use ValidationTrait;
+
+    /**
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     *
+     * @param array $args
+     *
+     * @return Response
+     */
+    public function __invoke(Request $request, Response $response, $args)
+    {
+        $this->preparePossibleRangeTypes();
+        $resource = \FeedbackElement::find($args['id']);
+        if (!$resource) {
+            throw new RecordNotFoundException();
+        }
+
+        $json = $this->validate($request);
+        $user = $this->getUser($request);
+
+        if (!Authority::canUpdateFeedbackElement($user, $resource)) {
+            throw new AuthorizationFailedException();
+        }
+
+        $feedbackElement = $this->update($resource, $json);
+
+        return $this->getContentResponse($feedbackElement);
+    }
+
+    /**
+     * @SuppressWarnings(PHPMD.UnusedFormalParameters)
+     *
+     * @param array $json
+     * @param mixed $data
+     *
+     * @return string|void
+     */
+    protected function validateResourceDocument($json, $data)
+    {
+        if (!self::arrayHas($json, 'data')) {
+            return 'Missing `data` member at document´s top level.';
+        }
+        if (FeedbackElementSchema::TYPE !== self::arrayGet($json, 'data.type')) {
+            return 'Invalid `type` of document´s `data`.';
+        }
+        if (!self::arrayHas($json, 'data.id')) {
+            return 'An existing document must have an `id`.';
+        }
+
+        $required = ['question', 'description', 'mode', 'results-visible', 'is-commentable'];
+        foreach ($required as $attribute) {
+            if (!self::arrayHas($json, 'data.attributes.' . $attribute)) {
+                return 'Missing `' . $attribute . '` attribute.';
+            }
+        }
+    }
+
+    private function update(FeedbackElement $feedbackElement, array $json): FeedbackElement
+    {
+        $strAttrs = ['question', 'description', 'mode'];
+        foreach ($strAttrs as $attribute) {
+            if (self::arrayHas($json, 'data.attributes.' . $attribute)) {
+                $feedbackElement[$attribute] = self::arrayGet($json, 'data.attributes.' . $attribute);
+            }
+        }
+
+        $boolAttrs = ['results-visible', 'is-commentable'];
+        foreach ($boolAttrs as $attribute) {
+            if (self::arrayHas($json, 'data.attributes.' . $attribute)) {
+                $feedbackElement[$attribute] = self::arrayGet($json, 'data.attributes.' . $attribute) ? 1 : 0;
+            }
+        }
+        $feedbackElement->store();
+
+        return $feedbackElement;
+    }
+}
diff --git a/lib/classes/JsonApi/Routes/Feedback/FeedbackEntriesCreate.php b/lib/classes/JsonApi/Routes/Feedback/FeedbackEntriesCreate.php
new file mode 100644
index 0000000000000000000000000000000000000000..0337ce4e2e1e018c7d028cde314b79b4f7c15fcb
--- /dev/null
+++ b/lib/classes/JsonApi/Routes/Feedback/FeedbackEntriesCreate.php
@@ -0,0 +1,112 @@
+<?php
+
+namespace JsonApi\Routes\Feedback;
+
+use FeedbackElement;
+use FeedbackEntry;
+use InvalidArgumentException;
+use User;
+use JsonApi\Errors\AuthorizationFailedException;
+use JsonApi\JsonApiController;
+use JsonApi\Routes\ValidationTrait;
+use JsonApi\Schemas\FeedbackElement as FeedbackElementSchema;
+use JsonApi\Schemas\FeedbackEntry as FeedbackEntrySchema;
+use Psr\Http\Message\ResponseInterface as Response;
+use Psr\Http\Message\ServerRequestInterface as Request;
+
+/**
+ * Create a FeedbackEntry.
+ *
+ * @SuppressWarnings(PHPMD.StaticAccess)
+ */
+class FeedbackEntriesCreate extends JsonApiController
+{
+    use RatingHelper;
+    use ValidationTrait;
+
+    /**
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     *
+     * @param array $args
+     *
+     * @return Response
+     */
+    public function __invoke(Request $request, Response $response, $args)
+    {
+        $json = $this->validate($request);
+        $element = $this->getElementFromJson($json);
+        $user = $this->getUser($request);
+
+        if (!Authority::canCreateFeedbackEntry($user, $element)) {
+            throw new AuthorizationFailedException();
+        }
+
+        $feedbackEntry = $this->create($user, $json);
+
+        return $this->getCreatedResponse($feedbackEntry);
+    }
+
+    /**
+     * @SuppressWarnings(PHPMD.UnusedFormalParameters)
+     *
+     * @param array $json
+     * @param mixed $data
+     *
+     * @return string|void
+     */
+    protected function validateResourceDocument($json, $data)
+    {
+        if (!self::arrayHas($json, 'data')) {
+            return 'Missing `data` member at document´s top level.';
+        }
+        if (FeedbackEntrySchema::TYPE !== self::arrayGet($json, 'data.type')) {
+            return 'Invalid `type` of document´s `data`.';
+        }
+        if (self::arrayHas($json, 'data.id')) {
+            return 'New document must not have an `id`.';
+        }
+
+        if (!self::arrayHas($json, 'data.relationships.feedback-element')) {
+            return 'Missing `feedback-element` relationship.';
+        }
+        if (!$this->getElementFromJson($json)) {
+            return 'Invalid `feedback-element` relationship.';
+        }
+
+        $required = ['rating'];
+        foreach ($required as $attribute) {
+            if (!self::arrayHas($json, 'data.attributes.' . $attribute)) {
+                return 'Missing `' . $attribute . '` attribute.';
+            }
+        }
+    }
+
+    private function getElementFromJson(array $json): ?FeedbackElement
+    {
+        $relationship = FeedbackEntrySchema::REL_FEEDBACK;
+        if (!$this->validateResourceObject($json, 'data.relationships.' . $relationship, FeedbackElementSchema::TYPE)) {
+            return null;
+        }
+        $resourceId = self::arrayGet($json, 'data.relationships.' . $relationship . '.data.id');
+
+        return FeedbackElement::find($resourceId);
+    }
+
+    private function create(User $user, array $json): FeedbackEntry
+    {
+        $element = $this->getElementFromJson($json);
+        $entry = \FeedbackEntry::build([
+            'feedback_id' => $element->getId(),
+            'user_id' => $user->getId(),
+            'rating' => $this->getRating($element, (int) self::arrayGet($json, 'data.attributes.rating')),
+        ]);
+
+        if ($element['commentable']) {
+            $entry['comment'] = self::arrayGet($json, 'data.attributes.comment', '');
+        }
+
+        $entry->store();
+
+        return $entry;
+    }
+}
diff --git a/lib/classes/JsonApi/Routes/Feedback/FeedbackEntriesDelete.php b/lib/classes/JsonApi/Routes/Feedback/FeedbackEntriesDelete.php
new file mode 100644
index 0000000000000000000000000000000000000000..7afcdb12ea143ee9316375bab7bb5f2c93f6f182
--- /dev/null
+++ b/lib/classes/JsonApi/Routes/Feedback/FeedbackEntriesDelete.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace JsonApi\Routes\Feedback;
+
+use FeedbackEntry;
+use Psr\Http\Message\ServerRequestInterface as Request;
+use Psr\Http\Message\ResponseInterface as Response;
+use JsonApi\Errors\AuthorizationFailedException;
+use JsonApi\Errors\RecordNotFoundException;
+use JsonApi\JsonApiController;
+
+/**
+ * Deletes a feedback entry.
+ *
+ * @SuppressWarnings(PHPMD.StaticAccess)
+ */
+class FeedbackEntriesDelete extends JsonApiController
+{
+    /**
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     *
+     * @param array $args
+     *
+     * @return Response
+     */
+    public function __invoke(Request $request, Response $response, $args)
+    {
+        $resource = FeedbackEntry::find($args['id']);
+        if (!$resource) {
+            throw new RecordNotFoundException();
+        }
+
+        if (!Authority::canDeleteFeedbackEntry($this->getUser($request), $resource)) {
+            throw new AuthorizationFailedException();
+        }
+        $resource->delete();
+
+        return $this->getCodeResponse(204);
+    }
+}
diff --git a/lib/classes/JsonApi/Routes/Feedback/FeedbackEntriesShow.php b/lib/classes/JsonApi/Routes/Feedback/FeedbackEntriesShow.php
index b591db3e1351e5ea1cf20660d078909686a7e6e4..4a85c69cdbe1a53635f439fb38e787c349ab69d7 100644
--- a/lib/classes/JsonApi/Routes/Feedback/FeedbackEntriesShow.php
+++ b/lib/classes/JsonApi/Routes/Feedback/FeedbackEntriesShow.php
@@ -7,19 +7,27 @@ use Psr\Http\Message\ResponseInterface as Response;
 use JsonApi\Errors\AuthorizationFailedException;
 use JsonApi\Errors\RecordNotFoundException;
 use JsonApi\JsonApiController;
+use JsonApi\Schemas\FeedbackEntry as FeedbackEntrySchema;
 
 /**
  * Displays a certain feedback entry.
  */
 class FeedbackEntriesShow extends JsonApiController
 {
-    protected $allowedIncludePaths = ['author', 'feedback-element'];
+    protected $allowedIncludePaths = [FeedbackEntrySchema::REL_AUTHOR, FeedbackEntrySchema::REL_FEEDBACK];
+
     /**
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     * @SuppressWarnings(PHPMD.StaticAccess)
+     *
+     * @param array $args
+     *
+     * @return Response
      */
     public function __invoke(Request $request, Response $response, $args)
     {
-        if (!$resource = \FeedbackEntry::find($args['id'])) {
+        $resource = \FeedbackEntry::find($args['id']);
+        if (!$resource) {
             throw new RecordNotFoundException();
         }
 
diff --git a/lib/classes/JsonApi/Routes/Feedback/FeedbackEntriesUpdate.php b/lib/classes/JsonApi/Routes/Feedback/FeedbackEntriesUpdate.php
new file mode 100644
index 0000000000000000000000000000000000000000..4fc408635a444a0631c57d60321f19692d2a19c6
--- /dev/null
+++ b/lib/classes/JsonApi/Routes/Feedback/FeedbackEntriesUpdate.php
@@ -0,0 +1,94 @@
+<?php
+
+namespace JsonApi\Routes\Feedback;
+
+use FeedbackElement;
+use FeedbackEntry;
+use User;
+use JsonApi\Errors\AuthorizationFailedException;
+use JsonApi\Errors\RecordNotFoundException;
+use JsonApi\JsonApiController;
+use JsonApi\Routes\ValidationTrait;
+use JsonApi\Schemas\FeedbackElement as FeedbackElementSchema;
+use JsonApi\Schemas\FeedbackEntry as FeedbackEntrySchema;
+use Psr\Http\Message\ResponseInterface as Response;
+use Psr\Http\Message\ServerRequestInterface as Request;
+
+/**
+ * Update a FeedbackEntry.
+ *
+ * @SuppressWarnings(PHPMD.StaticAccess)
+ */
+class FeedbackElementsUpdate extends JsonApiController
+{
+    use RatingHelper;
+    use ValidationTrait;
+
+    /**
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     *
+     * @param array $args
+     *
+     * @return Response
+     */
+    public function __invoke(Request $request, Response $response, $args)
+    {
+        $resource = \FeedbackEntry::find($args['id']);
+        if (!$resource) {
+            throw new RecordNotFoundException();
+        }
+
+        $json = $this->validate($request);
+        $user = $this->getUser($request);
+
+        if (!Authority::canUpdateFeedbackEntry($user, $resource)) {
+            throw new AuthorizationFailedException();
+        }
+
+        $feedbackEntry = $this->update($resource, $json);
+
+        return $this->getContentResponse($feedbackEntry);
+    }
+
+    /**
+     * @SuppressWarnings(PHPMD.UnusedFormalParameters)
+     *
+     * @param array $json
+     * @param mixed $data
+     *
+     * @return string|void
+     */
+    protected function validateResourceDocument($json, $data)
+    {
+        if (!self::arrayHas($json, 'data')) {
+            return 'Missing `data` member at document´s top level.';
+        }
+        if (FeedbackEntrySchema::TYPE !== self::arrayGet($json, 'data.type')) {
+            return 'Invalid `type` of document´s `data`.';
+        }
+        if (!self::arrayHas($json, 'data.id')) {
+            return 'An existing document must have an `id`.';
+        }
+
+        $required = ['rating'];
+        foreach ($required as $attribute) {
+            if (!self::arrayHas($json, 'data.attributes.' . $attribute)) {
+                return 'Missing `' . $attribute . '` attribute.';
+            }
+        }
+    }
+
+    private function update(FeedbackEntry $feedbackEntry, array $json): FeedbackEntry
+    {
+        $feedbackEntry->rating = $this->getRating(
+            $feedbackEntry->feedback,
+            (int) self::arrayGet($json, 'data.attributes.rating')
+        );
+        if ($feedbackEntry->feedback->commentable && self::arrayHas($json, 'data.attributes.comment')) {
+            $feedbackEntry->comment = self::arrayGet($json, 'data.attributes.comment');
+        }
+        $feedbackEntry->store();
+
+        return $feedbackEntry;
+    }
+}
diff --git a/lib/classes/JsonApi/Routes/Feedback/RangeTypeAware.php b/lib/classes/JsonApi/Routes/Feedback/RangeTypeAware.php
new file mode 100644
index 0000000000000000000000000000000000000000..88fd1b164b6d7f32d15b2b0ba83f62ea01050cfe
--- /dev/null
+++ b/lib/classes/JsonApi/Routes/Feedback/RangeTypeAware.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace JsonApi\Routes\Feedback;
+
+use FeedbackRange;
+use SimpleORMap;
+
+trait RangeTypeAware
+{
+    protected $possibleRangeTypes = null;
+
+    protected function preparePossibleRangeTypes(): void
+    {
+        foreach (app('json-api-integration-schemas') as $class => $schema) {
+            if (is_subclass_of($class, FeedbackRange::class) && is_subclass_of($class, SimpleORMap::class)) {
+                $this->possibleRangeTypes[$schema::TYPE] = $class;
+            }
+        }
+    }
+}
diff --git a/lib/classes/JsonApi/Routes/Feedback/RatingHelper.php b/lib/classes/JsonApi/Routes/Feedback/RatingHelper.php
new file mode 100644
index 0000000000000000000000000000000000000000..552d9fd7ecc108145d461ca56dcb270caa1d2ea8
--- /dev/null
+++ b/lib/classes/JsonApi/Routes/Feedback/RatingHelper.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace JsonApi\Routes\Feedback;
+
+use FeedbackElement;
+
+trait RatingHelper
+{
+    // TODO: Hier passt einiges nicht
+    private function getRating(FeedbackElement $element, int $rating): int
+    {
+        $mode = $element['mode'];
+        if ($mode === 0) {
+            return 0;
+        }
+
+        if ($rating === 0) {
+            return 1;
+        }
+
+        if ($mode === 1) {
+            return min(5, $rating);
+        }
+
+        if ($mode === 2) {
+            return min(10, $rating);
+        }
+
+        throw new InvalidArgumentException("Invalid mode {$mode}");
+    }
+}
diff --git a/lib/classes/JsonApi/Schemas/FeedbackElement.php b/lib/classes/JsonApi/Schemas/FeedbackElement.php
index 143bb0c1cf47776d38da16e3d6a4a0f26ebf28e3..41dc37075f1ba5c3983bcb635b0bdc81e083351e 100644
--- a/lib/classes/JsonApi/Schemas/FeedbackElement.php
+++ b/lib/classes/JsonApi/Schemas/FeedbackElement.php
@@ -2,24 +2,28 @@
 
 namespace JsonApi\Schemas;
 
+use JsonApi\Errors\InternalServerError;
 use Neomerx\JsonApi\Contracts\Schema\ContextInterface;
 use Neomerx\JsonApi\Schema\Link;
 
 class FeedbackElement extends SchemaProvider
 {
-    const TYPE = 'feedback-elements';
-    const REL_AUTHOR = 'author';
-    const REL_COURSE = 'course';
-    const REL_ENTRIES = 'entries';
-    const REL_RANGE = 'range';
+    public const TYPE = 'feedback-elements';
+    public const REL_AUTHOR = 'author';
+    public const REL_COURSE = 'course';
+    public const REL_ENTRIES = 'entries';
+    public const REL_RANGE = 'range';
 
 
 
     public function getId($resource): ?string
     {
-        return (int) $resource->id;
+        return (string) $resource->id;
     }
 
+    /**
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
     public function getAttributes($resource, ContextInterface $context): iterable
     {
         $attributes = [
@@ -76,7 +80,7 @@ class FeedbackElement extends SchemaProvider
         return $relationships;
     }
 
-    private function getAuthorRelationship(array $relationships, \FeedbackElement $resource, $includeData): array
+    private function getAuthorRelationship(array $relationships, \FeedbackElement $resource, bool $includeData): array
     {
         $userId = $resource['user_id'];
         $related = $includeData ? \User::find($userId) : \User::build(['id' => $userId], false);
@@ -90,7 +94,7 @@ class FeedbackElement extends SchemaProvider
         return $relationships;
     }
 
-    private function getCourseRelationship(array $relationships, \FeedbackElement $resource, $includeData): array
+    private function getCourseRelationship(array $relationships, \FeedbackElement $resource, bool $includeData): array
     {
         if ($courseId = $resource['course_id']) {
             $related = $includeData ? \Course::find($courseId) : \Course::build(['id' => $courseId], false);
@@ -119,23 +123,17 @@ class FeedbackElement extends SchemaProvider
 
     private function getRangeRelationship(array $relationships, \FeedbackElement $resource, bool $includeData): array
     {
-        $rangeType = $resource['range_type'];
-        $link = null;
-
+        $range = $resource->getRange();
         try {
-            $link = $this->createLinkToResource($rangeType);
-            if (
-                is_subclass_of($rangeType, \FeedbackRange::class) &&
-                is_subclass_of($rangeType, \SimpleORMap::class)
-            ) {
-                if ($range = $rangeType::find($resource['range_id'])) {
-                    $relationships[self::REL_RANGE] = [
-                        self::RELATIONSHIP_LINKS => [Link::RELATED => $link],
-                        self::RELATIONSHIP_DATA => $range
-                    ];
-                }
-            }
+            $link = $this->createLinkToResource($range);
+            $relationships[self::REL_RANGE] = [
+                self::RELATIONSHIP_LINKS => [Link::RELATED => $link],
+                self::RELATIONSHIP_DATA => $range
+            ];
         } catch (\InvalidArgumentException $e) {
+            // don't show this relation
+        } catch (InternalServerError $ise) {
+            // don't show this relation
         }
 
         return $relationships;