diff --git a/.idea/kubernetes-settings.xml b/.idea/kubernetes-settings.xml
index 0207c4b0843da6a8315f3419ea96141cdcdebe10..1ba17a0c33b44b03beea3ae22c5b829a2f7e32f6 100644
--- a/.idea/kubernetes-settings.xml
+++ b/.idea/kubernetes-settings.xml
@@ -9,4 +9,7 @@
       </list>
     </option>
   </component>
+  <component name="KubernetesSettings">
+    <option name="contextName" value="minikube" />
+  </component>
 </project>
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 2acfb33066ba1138f2ea4b1e9f0e2ecb3ff55250..99e50705225dace0c18e55b8a2fafab16815926c 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
   <component name="ExternalStorageConfigurationManager" enabled="true" />
   <component name="MavenProjectsManager">
diff --git a/moodle-assignsubmission-autograde/classes/dto/JobRequestDTO.php b/moodle-assignsubmission-autograde/classes/dto/JobRequestDTO.php
index baf5c2d536856011843632fd871ef617c25755a4..06bd3f7dc15613199831db20b3ac6b6ed2534e38 100644
--- a/moodle-assignsubmission-autograde/classes/dto/JobRequestDTO.php
+++ b/moodle-assignsubmission-autograde/classes/dto/JobRequestDTO.php
@@ -36,10 +36,6 @@ defined('MOODLE_INTERNAL') || die();
  */
 final class JobRequestDTO {
 
-    /** @var int ??? */
-    public int $userid;
-    /** @var int ??? */
-    public int $courseid;
     /** @var int ??? */
     public int $assignmentid;
     /** @var int ??? */
@@ -52,16 +48,12 @@ final class JobRequestDTO {
 
     /**
      * ???
-     * @param $userid ???
-     * @param $courseid ???
      * @param $assignmentid ???
      * @param $assignctxid ???
      * @param $submissionid ???
      * @param $image_name ???
      */
-    public function __construct($userid, $courseid, $assignmentid, $assignctxid, $submissionid, $image_name){
-        $this->userid = $userid;
-        $this->courseid = $courseid;
+    public function __construct($assignmentid, $assignctxid, $submissionid, $image_name){
         $this->assignmentid = $assignmentid;
         $this->assignctxid = $assignctxid;
         $this->submissionid = $submissionid;
diff --git a/moodle-assignsubmission-autograde/classes/dto/UploadCredentialsDTO.php b/moodle-assignsubmission-autograde/classes/dto/UploadCredentialsDTO.php
index 66e37f06a46d84b703d182743a30724c51e17d2f..3e1dafa92d2569a45eaa2a33c3826d3ba1f72887 100644
--- a/moodle-assignsubmission-autograde/classes/dto/UploadCredentialsDTO.php
+++ b/moodle-assignsubmission-autograde/classes/dto/UploadCredentialsDTO.php
@@ -36,9 +36,6 @@ defined('MOODLE_INTERNAL') || die();
  */
 final class UploadCredentialsDTO {
 
-    /** @var int ??? */
-    public int $courseid;
-
     /** @var int ??? */
     public int $assignmentid;
 
@@ -49,12 +46,10 @@ final class UploadCredentialsDTO {
 
     /**
      * ???
-     * @param $courseid ???
      * @param $assignmentid ???
      * @param $assignctxid ???
      */
-    public function __construct($courseid, $assignmentid, $assignctxid){
-        $this->courseid     = $courseid;
+    public function __construct($assignmentid, $assignctxid){
         $this->assignmentid = $assignmentid;
         $this->assignctxid  = $assignctxid;
     }
diff --git a/moodle-assignsubmission-autograde/classes/external/autograde_download_credentials.php b/moodle-assignsubmission-autograde/classes/external/autograde_download_credentials.php
index 84a5ab38be092817d4fee56eb2dd34af299e5795..f451d17929c8f0a43076a4897507cafee0aaad33 100644
--- a/moodle-assignsubmission-autograde/classes/external/autograde_download_credentials.php
+++ b/moodle-assignsubmission-autograde/classes/external/autograde_download_credentials.php
@@ -59,7 +59,6 @@ final class autograde_download_credentials extends external_api {
      */
     public static function download_credentials_parameters(): external_function_parameters {
         return new external_function_parameters([
-            'courseid' => new external_value(PARAM_INT, 'Course ID'),
             'assignmentid' => new external_value(PARAM_INT, 'Assignment ID'),
             'assignctxid' => new external_value(PARAM_INT, "Assignment's context ID")
         ]);
@@ -73,11 +72,13 @@ final class autograde_download_credentials extends external_api {
      * @throws coding_exception ???
      * @throws moodle_exception ???
      */
-    public static function download_credentials($courseid, $assignmentid, $assignctxid): object {
-        global $USER;
+    public static function download_credentials($assignmentid, $assignctxid): object {
+        global $DB, $USER;
+        // HR : Fetch the course's id from the assignment definition
+        $course_id = $DB->get_field('assign', 'course', array('id' => $assignmentid));
         // HR : Check the necessary capabilities
         require_capability('mod/assign/submission/autograde:read_credentials',
-            context_course::instance($courseid), $USER->id, false);
+            context_course::instance($course_id), $USER->id, false);
 
         $fs = get_file_storage();
         $files = $fs->get_area_files(
diff --git a/moodle-assignsubmission-autograde/classes/external/autograde_download_submission.php b/moodle-assignsubmission-autograde/classes/external/autograde_download_submission.php
index ccb4f1b64d7f17777f02551d36005d5337be979a..80da93c58025c6a2bb892ce49aa8a287f78dc8d3 100644
--- a/moodle-assignsubmission-autograde/classes/external/autograde_download_submission.php
+++ b/moodle-assignsubmission-autograde/classes/external/autograde_download_submission.php
@@ -59,7 +59,6 @@ final class autograde_download_submission extends external_api {
      */
     public static function download_submission_parameters() {
         return new external_function_parameters([
-            'courseid' => new external_value(PARAM_INT, 'Course ID'),
             'submissionid' => new external_value(PARAM_INT, 'Submission ID'),
             'assignctxid' => new external_value(PARAM_INT, "Assignment's context ID")
         ]);
@@ -67,17 +66,20 @@ final class autograde_download_submission extends external_api {
 
     /**
      * ???
-     * @param $courseid ???
      * @param $submissionid ???
      * @return stdClass ???
      * @throws coding_exception ???
      * @throws moodle_exception ???
      */
-    public static function download_submission($courseid, $submissionid, $assignctxid): stdClass {
-        global $USER;
+    public static function download_submission($submissionid, $assignctxid): stdClass {
+        global $DB, $USER;
+        // HR : Fetch the assignment's and course's ids linked to the assignment
+        $assignment_id = $DB->get_field('assign_submission', 'assignment', array('id' => $submissionid));
+        $course_id = $DB->get_field('assign', 'course', array('id' => $assignment_id));
+
         // HR : Check if the user has the necessary capabilities
         require_capability('mod/assign/submission/autograde:read_submission',
-            context_course::instance($courseid), $USER->id, false);
+            context_course::instance($course_id), $USER->id, false);
 
         // HR : Retrieve the files associated with the specified area and item
         $fs = get_file_storage();
diff --git a/moodle-assignsubmission-autograde/classes/external/autograde_upload_feedback.php b/moodle-assignsubmission-autograde/classes/external/autograde_upload_feedback.php
index 4df5363b8b5bd3aeda0d12ac645a507dfcf4300e..d64045d01dad8cf10b6ed1b1c7b19f8dcfec9fb9 100644
--- a/moodle-assignsubmission-autograde/classes/external/autograde_upload_feedback.php
+++ b/moodle-assignsubmission-autograde/classes/external/autograde_upload_feedback.php
@@ -62,10 +62,7 @@ final class autograde_upload_feedback extends external_api {
      */
    public static function upload_feedback_parameters() {
        return new external_function_parameters([
-           'userid' => new external_value(PARAM_INT, 'The user ID'),
-           'courseid' => new external_value(PARAM_INT, 'The user ID'),
-           'assignmentid' => new external_value(PARAM_INT, 'The user ID'),
-           'assignctxid' => new external_value(PARAM_INT, 'The user ID'),
+           'assignctxid' => new external_value(PARAM_INT, "assign context's id"),
            'submissionid' => new external_value(PARAM_INT, 'The user ID'),
            'grade' => new external_value(PARAM_INT, 'The user ID'),
            'feedback' => new external_value(PARAM_TEXT, 'The feedback message'),
@@ -74,9 +71,6 @@ final class autograde_upload_feedback extends external_api {
 
     /**
      * ???
-     * @param $userid ???
-     * @param $courseid ???
-     * @param $assignmentid ???
      * @param $submissionid ???
      * @param $grade ???
      * @param $feedback ???
@@ -84,31 +78,28 @@ final class autograde_upload_feedback extends external_api {
      * @throws dml_exception ???
      * @throws required_capability_exception ???
      */
-   public static function upload_feedback (
-       $userid, $courseid,
-       $assignmentid, $assignctxid, $submissionid,
-       $grade, $feedback
-   ) {
-
-       global $USER, $DB;
-
+   public static function upload_feedback($assignctxid, $submissionid, $grade, $feedback) {
+       global $DB, $USER;
+       // HR : Fetch all the necessary ids to upload correctly the feedback
+       $assignment_id = $DB->get_field('assign_submission', 'assignment', array('id' => $submissionid));
+       $user_id = $DB->get_field('assign_submission', 'userid', array('id' => $submissionid));
+       $course_id = $DB->get_field('assign', 'course', array('id' => $assignment_id));
+
+       // HR : Check the necessary capabilities are present
        require_capability('mod/assign/submission/autograde:update_feedback',
-           context_course::instance($courseid), $USER->id, false);
-
-       // HR : Fetch the metadata of the submission
-       $submission = $DB->get_record('assign_submission', array('id' => $submissionid));
+           context_course::instance($course_id), $USER->id, false);
 
-       $grade_item = grade_item::fetch(['itemmodule' => 'assign', 'iteminstance' => $assignmentid]);
+       $grade_item = grade_item::fetch(['itemmodule' => 'assign', 'iteminstance' => $assignment_id]);
        if(!$grade_item){
            throw new coding_exception("grade_item not found");
        }
 
        $gradegradedata = new stdClass();
        $gradegradedata->itemid = $grade_item->id;
-       $gradegradedata->userid = $submission->userid;
+       $gradegradedata->userid = $user_id;
        $gradegradedata->rawgrade = $grade;
        $gradegradedata->finalgrade = $grade;
-       $gradegradedata->usermodified = $userid;
+       $gradegradedata->usermodified = $user_id;
        $gradegradedata->hidden = 0;
        $gradegradedata->timecreated = time();
        $gradegradedata->timemodified = time();
@@ -118,7 +109,7 @@ final class autograde_upload_feedback extends external_api {
        // HR : Update the grade in the gradebook
        grade_update(
            'mod/assign',
-           $courseid,
+           $course_id,
            'mod',
            'assign',
            $grade_item->iteminstance,
@@ -133,7 +124,7 @@ final class autograde_upload_feedback extends external_api {
            'filearea' => ASSIGNSUBMISSION_AUTOGRADE_FEEDBACK_FILEAREA,
            'itemid' => $submissionid,
            'filepath' => '/',
-           'filename' => 'feedback-'. $assignmentid . '-' .$submissionid.'.json'
+           'filename' => 'feedback-'. $assignment_id . '-' .$submissionid.'.json'
        );
        get_file_storage()->create_file_from_string($file_info, $feedback);
        return true;
diff --git a/moodle-assignsubmission-autograde/locallib.php b/moodle-assignsubmission-autograde/locallib.php
index f8cae1270c47b319130d75fa2708ef8d22bcbfb5..d510f5d7b88947a9c32c5a7a8d6efd51529965a9 100644
--- a/moodle-assignsubmission-autograde/locallib.php
+++ b/moodle-assignsubmission-autograde/locallib.php
@@ -139,7 +139,6 @@ final class assign_submission_autograde extends assign_submission_plugin {
      */
     public function save_settings(stdClass $data): bool {
         // HR : Store the Docker image in the configuration
-        global $COURSE, $DB;
         $this->set_config(self::setting_docker_image_id, $data->docker_image);
         // HR : Store the WebService API_KEY in the configuration setting
         $this->set_config(self::setting_webservice_key_id, $data->webservice_key);
@@ -159,7 +158,6 @@ final class assign_submission_autograde extends assign_submission_plugin {
         $autograde_webservice = new autograde_webservice($this->autograde_api_key());
         $request =
             new UploadCredentialsDTO(
-                $COURSE->id,
                 $this->assignment->get_instance()->id,
                 $this->assignment->get_context()->id
             );
@@ -261,7 +259,6 @@ final class assign_submission_autograde extends assign_submission_plugin {
      * @throws dml_exception ???
      */
     public function save(stdClass $submissionorgrade, stdClass $data): bool {
-        global $USER, $COURSE;
 
         // HR : Save the files (before, they were marked as Draft)
         // HR : Without this step, the download_submission webservice won't work
@@ -279,8 +276,6 @@ final class assign_submission_autograde extends assign_submission_plugin {
         // HR : Request from autograde to grade the submission
         $request =
             new JobRequestDTO(
-                $USER->id,
-                $COURSE->id,
                 $this->assignment->get_instance()->id,
                 $this->assignment->get_context()->id,
                 $submissionorgrade->id,
diff --git a/moodle-assignsubmission-autograde/settings.php b/moodle-assignsubmission-autograde/settings.php
index 35c8e8f76ff9abbabb11db2ebf6e6d5cd1636cfc..92894304147c8937be4c680d1089b7bab8b323cd 100644
--- a/moodle-assignsubmission-autograde/settings.php
+++ b/moodle-assignsubmission-autograde/settings.php
@@ -25,6 +25,8 @@
 
 defined('MOODLE_INTERNAL') || die();
 
+require_once(__DIR__ . '/lib.php');
+
 $settings->add(
     new admin_setting_configtext("assignsubmission_autograde/service_url",
         get_string('admin_setting_url', ASSIGNSUBMISSION_AUTOGRADE_COMPONENT_NAME),
diff --git a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/config/KubernetesConfig.java b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/config/KubernetesConfig.java
index 01d92938931f5fefcbc2e36063e7649e5e595b87..3e7385b4a7411d351781eb6b76b44a8781eb7d55 100644
--- a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/config/KubernetesConfig.java
+++ b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/config/KubernetesConfig.java
@@ -5,11 +5,19 @@ import io.fabric8.kubernetes.client.KubernetesClientBuilder;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 
+/**
+ * Configuration and setup of the underlying kubernetes cluster
+ *
+ * @author Dixit Sabharwal (dixit.sabharwal@epfl.ch)
+ * @since 1.0
+ */
 @Configuration
 public class KubernetesConfig {
 
+    /** Provide a client to communicate to the underlying kubernetes cluster */
     @Bean
     public KubernetesClient kubernetesClient() {
         return new KubernetesClientBuilder().build();
     }
+
 }
diff --git a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/config/SecurityConfig.java b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/config/SecurityConfig.java
index 8db96b3ddf255815a7497551812ade10cbd4a5cd..934c58e74a6536506085fb729e1450a4c2af4c86 100644
--- a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/config/SecurityConfig.java
+++ b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/config/SecurityConfig.java
@@ -11,24 +11,24 @@ import org.springframework.security.web.SecurityFilterChain;
 import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
 
 /**
- * ???
+ * Security configuration and setup of the autograde service.
  *
  * @author Hamza REMMAL (hamza.remmal@epfl.ch)
+ * @since 1.0
  */
 @Configuration
 @EnableWebSecurity
 public class SecurityConfig {
 
-    /** ??? */
-    private final ApiKeyAuthenticationFilter apiKeyAuthFilter;
+    /** autograde custom API-KEY authentication filter */
+    private final ApiKeyAuthenticationFilter auth;
 
     /**
-     * ???
-     * @param apiKeyAuthFilter ???
+     * @param auth autograde authentication filter
      */
     @Autowired
-    public SecurityConfig(ApiKeyAuthenticationFilter apiKeyAuthFilter) {
-        this.apiKeyAuthFilter = apiKeyAuthFilter;
+    public SecurityConfig(ApiKeyAuthenticationFilter auth) {
+        this.auth = auth;
     }
 
     /**
@@ -41,7 +41,7 @@ public class SecurityConfig {
     public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
         return http
                 // HR : Add the ApiKeyAuthentication filter
-                .addFilterAfter(apiKeyAuthFilter, BasicAuthenticationFilter.class)
+                .addFilterAfter(auth, BasicAuthenticationFilter.class)
                 // HR : Disable CSRF
                 .csrf(AbstractHttpConfigurer::disable)
                 // HR : Configure the end points authorizations
diff --git a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/controller/FeedbackController.java b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/controller/FeedbackController.java
new file mode 100644
index 0000000000000000000000000000000000000000..037955fd64645fe0c874c837f22eec7da85e061a
--- /dev/null
+++ b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/controller/FeedbackController.java
@@ -0,0 +1,82 @@
+package ch.epfl.cs107.grading.moodle.api.v1.controller;
+
+import ch.epfl.cs107.grading.moodle.api.v1.dto.UploadFeedbackDTO;
+import ch.epfl.cs107.grading.moodle.api.v1.service.MoodleWebService;
+import ch.epfl.cs107.grading.moodle.api.v1.service.IntegrityService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * REST Controller to upload an autograde feedback to Moodle.
+ *
+ * @author Hamza REMMAL (hamza.remmal@epfl.ch)
+ * @since 1.0
+ */
+@RestController
+@RequestMapping("/api/v1/feedback")
+public final class FeedbackController {
+
+    private final Logger logger = LoggerFactory.getLogger(FeedbackController.class);
+
+    /** Service to generate and check the integrity of the requests */
+    private final IntegrityService integrity;
+
+    /** Service to communicate with Moodle */
+    private final MoodleWebService moodle;
+
+    /**
+     * @param moodle service to use to communicate with Moodle.
+     * @param integrity service to use for the integrity checks.
+     */
+    @Autowired
+    public FeedbackController(MoodleWebService moodle, IntegrityService integrity) {
+        this.moodle = moodle;
+        this.integrity = integrity;
+    }
+
+    /**
+     * Endpoint to upload an autograde feedback to Moodle
+     *
+     * @param submissionid ID of the submission on Moodle
+     * @param signature    HMAC of the request as generated by the autograde-service
+     * @param feedback     Autograde compatible feedback
+     * @since 1.0
+     * @apiNote This end point should only be called by the autograde-service itself
+     */
+    @PostMapping("/upload")
+    public ResponseEntity<?> submitGrade(
+            @RequestParam int assignctxid,
+            @RequestParam int submissionid,
+            @RequestParam String signature,
+            @RequestBody UploadFeedbackDTO feedback
+    ) {
+        logger.info("Received an 'upload feedback' request for submission with id {}", submissionid);
+        // HR : Check the integrity of the request
+        if (!integrity.check(signature, submissionid)) {
+            logger.error("Integrity check failed for 'upload feedback' request for submission {}", submissionid);
+            return ResponseEntity
+                    .status(HttpStatus.UNAUTHORIZED)
+                    .body("The provided signature is not correct !");
+        }
+        logger.info("Integrity check for 'upload feedback' request for submission {} was successful", submissionid);
+        // HR : Upload the grade and feedback to Moodle
+        try {
+            var res = moodle.upload_feedback(assignctxid, submissionid, feedback.getGrade(), feedback.getFeedback().toJson());
+            if (res.statusCode() != HttpStatus.OK.value()) {
+                throw new Exception("Moodle request returned with status: " + res.statusCode() + " " + res.body());
+            } else {
+                // HR : Request was successful
+                logger.info("Feedback was successfully stored on Moodle for submission with id {}", submissionid);
+                return ResponseEntity.ok().build();
+            }
+        } catch (Exception e) {
+            logger.error("Failed to upload the grade and feedback to Moodle for submission with id {}", submissionid, e);
+            return ResponseEntity.internalServerError().build();
+        }
+    }
+
+}
diff --git a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/controller/GradingController.java b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/controller/GradingController.java
index c4f41526d9384dae0b7213f0f7cc5215e229baed..1ecf869bb2c36c9028f58baaff32c92ae641cf90 100644
--- a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/controller/GradingController.java
+++ b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/controller/GradingController.java
@@ -1,126 +1,66 @@
 package ch.epfl.cs107.grading.moodle.api.v1.controller;
 
 import ch.epfl.cs107.grading.moodle.api.v1.dto.GradeRequestDTO;
-import ch.epfl.cs107.grading.moodle.api.v1.dto.UploadFeedbackDTO;
-import ch.epfl.cs107.grading.moodle.api.v1.service.KubernetesJobService;
-import ch.epfl.cs107.grading.moodle.api.v1.service.MoodleWebService;
-import ch.epfl.cs107.grading.moodle.api.v1.service.SubmissionIntegrityService;
+import ch.epfl.cs107.grading.moodle.api.v1.service.KubernetesService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
 
 /**
- * Handles grading requests from moodle and submit grades and feedback to
- * moodle.
+ * REST Controller to request an autograde grading for a given submission
  *
  * @author Hamza REMMAL (hamza.remmal@epfl.ch)
+ * @since 1.0
  */
 @RestController
 @RequestMapping("/api/v1/grading")
-public class GradingController {
+public final class GradingController {
 
     private final Logger logger = LoggerFactory.getLogger(GradingController.class);
 
-    /**
-     * Send requests to moodle
-     */
-    private final MoodleWebService moodleWebService;
-
-    /**
-     * Trigger jobs on kubernetes cluster
-     */
-    private final KubernetesJobService kubernetesJobService;
+    /** Service to communicate with the k8s cluster */
+    private final KubernetesService k8s;
 
     /**
-     * Check the integrity of the result submission requests
+     * @param k8s service to use to communicate with the k8s cluster.
      */
-    private final SubmissionIntegrityService integrity;
-
-
     @Autowired
-    public GradingController(MoodleWebService moodleWebService,
-                             KubernetesJobService kubernetesJobService,
-                             SubmissionIntegrityService integrity) {
-        this.moodleWebService = moodleWebService;
-        this.kubernetesJobService = kubernetesJobService;
-        this.integrity = integrity;
+    public GradingController(KubernetesService k8s) {
+        this.k8s = k8s;
     }
 
     /**
-     * Handles grading requests from moodle. Creates a grading job on the kubernetes
-     * cluster.
+     * Endpoint to request the grading of an autograde compatible submission
      *
-     * @param request ???
-     * @return ???
+     * @param request Grading request with the necessary information
+     * @return HTTP.OK with the job name in the body if successful,
+     *         HTTP.INTERNAL_ERROR otherwise
+     * @since 1.0
      */
     @PostMapping("/grade")
     public ResponseEntity<?> grade(@RequestBody GradeRequestDTO request) {
-
-        logger.info("Grading request received: {}", request.toString());
-
+        logger.info("Received request to grade submission with id {}", request.getSubmissionid());
         try {
-            var jobName = kubernetesJobService.createJob(
-                    request.getUserid(), request.getCourseid(),
-                    request.getAssignmentid(), request.getSubmissionid(),
-                    request.getAssignctxid(), request.getImage_name());
+            // TODO HR : createJob should take the request as parameter
+            var jobName = k8s.createJob(request.getAssignmentid(),
+                    request.getSubmissionid(),
+                    request.getAssignctxid(),
+                    request.getImage_name()
+            );
 
-            logger.info("Grading job created: {}", jobName);
-            return ResponseEntity.ok(jobName);
+            logger.info("Grading submission with id {} will be carried out by job with name {}",
+                    request.getSubmissionid(), jobName);
+            return ResponseEntity
+                    .ok(jobName);
         } catch (RuntimeException e) {
-            logger.error("Failed to create grading job", e);
-            return ResponseEntity.internalServerError().body("Failed to create grading job");
-        }
-    }
-
-    /**
-     * Handles requests from grading job to submit grades and feedback. Uploads
-     * grades and feedback to moodle.
-     *
-     * @param userid       ???
-     * @param courseid     ???
-     * @param assignmentid ???
-     * @param submissionid ???
-     * @param signature    ???
-     * @param feedback     ???
-     */
-    @PostMapping("/result")
-    public ResponseEntity<?> submitGrade(
-            @RequestParam int userid,
-            @RequestParam int courseid,
-            @RequestParam int assignmentid,
-            @RequestParam int assignctxid,
-            @RequestParam int submissionid,
-            @RequestParam String signature,
-            @RequestBody UploadFeedbackDTO feedback
-    ) {
-        if (!integrity.check(signature, courseid, submissionid)) {
-            logger.error("The provided signature to submit grade is not correct !");
-            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("The provided signature is not correct !");
-        }
-
-        logger.info("Grade/feedback submitted by job: userid={} courseid={} assignmentid={} submissionid={}",
-                userid, courseid, assignmentid, submissionid
-        );
-        try {
-            // HR : Upload grade and feedback to moodle
-            var res = moodleWebService.uploadAutoGradeFeedback(
-                    userid, courseid, assignmentid, assignctxid, submissionid,
-                    feedback.getGrade(), feedback.getFeedback().toJson());
-            if (res.statusCode() != HttpStatus.OK.value()) {
-                throw new Exception("Moodle request returned with status: " + res.statusCode() + " " + res.body());
-            }
-        } catch (Exception e) {
-            logger.error("Failed to upload grade and feedback to moodle: userid={} courseid={} assignmentid={} submissionid={}",
-                    userid, courseid, assignmentid, submissionid,
-                    e
-            );
+            logger.error("Failed to create a grading job to grade submission with id {}",
+                    request.getSubmissionid(), e);
+            return ResponseEntity
+                    .internalServerError()
+                    .body("Failed to create grading job");
         }
-        logger.info("Feedback submitted successfully: userid={} courseid={} assignmentid={} submissionid={}",
-                userid, courseid, assignmentid, submissionid);
-        return ResponseEntity.ok().build();
     }
 
 }
diff --git a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/controller/PingController.java b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/controller/PingController.java
index f9104bb578f28448db7d3a81ff4158f241d5672b..56346c2c64e98a42770b9d3f3083f1bda48a27bc 100644
--- a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/controller/PingController.java
+++ b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/controller/PingController.java
@@ -7,36 +7,40 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 /**
- * ???
+ * REST Controller for '/api/v1/ping' and provide end points
+ * to ping the autograde-service in different modes.
  *
  * @author Hamza REMMAL (hamza.remmal@epfl.ch)
+ * @since 1.0
  */
 @RestController
 @RequestMapping("/api/v1/ping")
-public class PingController {
+public final class PingController {
 
-    private Logger logger = LoggerFactory.getLogger(PingController.class);
+    private final Logger logger = LoggerFactory.getLogger(PingController.class);
 
     /**
-     * ???
-     *
-     * @return ???
+     * Endpoint to ping the service without authentication
+     * @return greetings from the service
+     * @since 1.0
      */
     @GetMapping("/no-auth")
     public String pingWithoutAuth() {
-        logger.info("Received a ping without auth");
-        return "Hello from Spring boot - No Auth mode";
+        logger.info("Received a ping from an unauthenticated source");
+        return "Hello and welcome to the autograde-service API. " +
+                "You have successfully pinged the service in no-auth mode.";
     }
 
     /**
-     * ???
-     *
-     * @return ???
+     * Endpoint to ping the service when authenticated
+     * @return greetings from the service
+     * @since 1.0
      */
     @GetMapping("/auth")
     public String pingWithAuth() {
-        logger.info("Received a ping");
-        return "Hello from Spring boot - Auth mode";
+        logger.info("Received a ping from an authenticated source");
+        return "Hello and welcome to the autograde-service API. " +
+                "You have successfully pinged the service in auth mode.";
     }
 
 }
diff --git a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/controller/RegistryCredentialsController.java b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/controller/RegistryCredentialsController.java
index 3dfa6abbdd03b5d622271b87f387012babc44031..e08da85de6778f978a4873922711afc9f1fefaab 100644
--- a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/controller/RegistryCredentialsController.java
+++ b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/controller/RegistryCredentialsController.java
@@ -1,7 +1,7 @@
 package ch.epfl.cs107.grading.moodle.api.v1.controller;
 
 import ch.epfl.cs107.grading.moodle.api.v1.dto.UploadCredentialsDTO;
-import ch.epfl.cs107.grading.moodle.api.v1.service.KubernetesJobService;
+import ch.epfl.cs107.grading.moodle.api.v1.service.KubernetesService;
 import ch.epfl.cs107.grading.moodle.api.v1.service.MoodleWebService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -12,13 +12,13 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
-import java.util.Arrays;
 import java.util.Base64;
 
 /**
- * ???
+ * REST Controller to manage the credentials stored in the cluster.
  *
  * @author Hamza REMMAL (hamza.remmal@epfl.ch)
+ * @since 1.0
  */
 @RestController
 @RequestMapping("/api/v1/registry/credentials")
@@ -26,54 +26,43 @@ public final class RegistryCredentialsController {
 
     private final Logger logger = LoggerFactory.getLogger(RegistryCredentialsController.class);
 
-    /**
-     * ???
-     */
-    private final KubernetesJobService k8s;
+    /** Service to communicate with the k8s cluster */
+    private final KubernetesService k8s;
 
-    /**
-     * ???
-     */
+    /** Service to communicate with Moodle */
     private final MoodleWebService moodle;
 
     /**
-     * ???
-     *
-     * @param k8s ???
+     * @param k8s service to use to communicate with the k8s cluster.
+     * @param moodle service to use to communicate with Moodle.
      */
     @Autowired
-    public RegistryCredentialsController(KubernetesJobService k8s, MoodleWebService moodle) {
+    public RegistryCredentialsController(KubernetesService k8s, MoodleWebService moodle) {
         this.k8s = k8s;
         this.moodle = moodle;
     }
 
     /**
-     * ???
-     *
-     * @return ???
+     * Endpoint to store the image registry credentials in the cluster.
+     * @return HTTP.OK if successful, HTTP.INTERNAL_ERROR if not.
+     * @since 1.0
      */
     @PostMapping("/upload")
     public ResponseEntity<?> uploadCredentials(@RequestBody UploadCredentialsDTO credentials) {
-        logger.info("Received credentials upload request for course {} and assignment {}",
-                credentials.getCourseid(), credentials.getAssignmentid());
-        logger.debug("Credentials for course {} and assignment {} are {}",
-                credentials.getCourseid(), credentials.getAssignmentid(), credentials);
+        logger.info("Received request to store the credentials for assignment {}", credentials.getAssignmentid());
 
         //try (var dockerconfigjson = moodle.download_credentials(credentials.getCourseid(), credentials.getAssignmentid(), credentials.getAssignctxid())) {
         try {
             k8s.tryCreateImagePullSecret(
                     //new String(dockerconfigjson.readAllBytes()),
                     new String(Base64.getDecoder().decode(credentials.getContent())),
-                    credentials.getCourseid(),
                     credentials.getAssignmentid());
 
-            logger.info("Successfully created ImagePullSecret for course {} and assignment {}",
-                    credentials.getCourseid(), credentials.getAssignmentid());
-            return ResponseEntity.ok().body(null);
+            logger.info("Successfully stored the credentials for assignment {}", credentials.getAssignmentid());
+            return ResponseEntity.ok().build();
         } catch (Exception e) {
-            logger.error("Failed to create ImagePullSecret for course {} and assignment {}",
-                    credentials.getCourseid(), credentials.getAssignmentid(), e);
-            return ResponseEntity.internalServerError().body("Failed to store credentials");
+            logger.error("Failed to store the credentials for assignment {}", credentials.getAssignmentid(), e);
+            return ResponseEntity.internalServerError().body("Failed to store credentials in the cluster");
         }
     }
 
diff --git a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/controller/SubmissionController.java b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/controller/SubmissionController.java
index a5e880423803554dfe7be70ff169fd6b64bcf313..8a43f5bccdfa13b975de1bb7ca2d54d9a4eb2582 100644
--- a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/controller/SubmissionController.java
+++ b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/controller/SubmissionController.java
@@ -1,7 +1,7 @@
 package ch.epfl.cs107.grading.moodle.api.v1.controller;
 
 import ch.epfl.cs107.grading.moodle.api.v1.service.MoodleWebService;
-import ch.epfl.cs107.grading.moodle.api.v1.service.SubmissionIntegrityService;
+import ch.epfl.cs107.grading.moodle.api.v1.service.IntegrityService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -14,77 +14,79 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
-import java.io.IOException;
-import java.net.URISyntaxException;
-
 import static org.springframework.http.HttpHeaders.CONTENT_TYPE;
 import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE;
 
 /**
- * ???
+ * REST Controller to fetch an autograde compatible submission from Moodle.
  *
  * @author Hamza REMMAL (hamza.remmal@epfl.ch)
+ * @since 1.0
  */
 @RestController
 @RequestMapping("/api/v1/submission")
-public class SubmissionController {
+public final class SubmissionController {
 
     private final Logger logger = LoggerFactory.getLogger(SubmissionController.class);
 
-    /**
-     * ???
-     */
+    /** Service to communicate with Moodle */
     private final MoodleWebService moodle;
 
-    private final SubmissionIntegrityService integrity;
+    /** Service to generate and check the integrity of the requests */
+    private final IntegrityService integrity;
 
     /**
-     * ???
-     *
-     * @param moodle ???
+     * @param moodle service to use to communicate with Moodle.
+     * @param integrity service to use for the integrity checks.
      */
     @Autowired
-    public SubmissionController(MoodleWebService moodle, SubmissionIntegrityService integrity) {
+    public SubmissionController(MoodleWebService moodle, IntegrityService integrity) {
         this.moodle = moodle;
         this.integrity = integrity;
     }
 
-
     /**
-     * ???
+     * Endpoint to download a given autograde compatible submission from Moodle.
      *
-     * @return ???
+     * @param submissionid ID of the submission in Moodle
+     * @param assignctxid ID of the context in Moodle
+     * @param signature HMAC of the request as generated by the autograde-service
+     * @return HTTP.OK with the submission if successful,
+     *         HTTP.UNAUTHORIZED if the HMAC is wrong
+     *         HTTP.INTERNAL_ERROR otherwise.
+     * @since 1.0
+     * @apiNote This end point should only be called by the autograde-service itself
      */
     @GetMapping("/download")
-    public ResponseEntity<?> download(@RequestParam int courseid,
-                                      @RequestParam int submissionid,
+    public ResponseEntity<?> download(@RequestParam int submissionid,
                                       @RequestParam int assignctxid,
                                       @RequestParam String signature) {
-
-        logger.info("Received submission download request for course {} and submission {}",
-                courseid, submissionid);
+        logger.info("Received a 'download submission' request for submission {}", submissionid);
 
         // HR : Check the integrity of the signature
-        if (!integrity.check(signature, courseid, submissionid))
-            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("The provided signature is not correct !");
-
+        if (!integrity.check(signature, submissionid)){
+            logger.error("Integrity check failed for 'download submission' request for submission {}", submissionid);
+            return ResponseEntity
+                    .status(HttpStatus.UNAUTHORIZED)
+                    .body("The provided signature is not correct !");
+        }
+        logger.info("Integrity check for 'download submission' request for submission {} was successful", submissionid);
         // HR : Serve the actual file, the integrity of the signature was checked
-        try (var file = moodle.download_submission(courseid, submissionid, assignctxid)) {
+        try (var file = moodle.download_submission(submissionid, assignctxid)) {
             // HR : Prepare the headers
             var headers = new HttpHeaders();
             headers.add(CONTENT_TYPE, APPLICATION_OCTET_STREAM_VALUE);
-
-            // HR : Prepare the body
-            var body = new InputStreamResource(file);
-
-            logger.info("Submission download request for course {} and submission {} served successfully",
-                    courseid, submissionid);
             // HR : Build response
-            return ResponseEntity.ok().headers(headers).body(body);
-        } catch (URISyntaxException | InterruptedException | IOException e) {
-            logger.error("An error occurred while downloading the submission courseid={}, submissionid={} from moodle",
-                    courseid, submissionid, e);
-            return ResponseEntity.internalServerError().body("An error occurred while downloading the submission !");
+            logger.info("'download submission' request for submission with id {} is served successfully", submissionid);
+            return ResponseEntity
+                    .ok()
+                    .headers(headers)
+                    .body(new InputStreamResource(file));
+        } catch (Exception e) {
+            logger.error("Failed to fetch the submission with id {} from Moodle", submissionid, e);
+            return ResponseEntity
+                    .internalServerError()
+                    .body("An error occurred while downloading the submission !");
         }
     }
 
diff --git a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/dto/GradeRequestDTO.java b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/dto/GradeRequestDTO.java
index 6aa6dcb8d4377254b792a5756c6a4d101e9f253b..4df9156729dabb58f24efbc47ab1e00eb4cd8d9c 100644
--- a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/dto/GradeRequestDTO.java
+++ b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/dto/GradeRequestDTO.java
@@ -8,12 +8,6 @@ import lombok.Data;
 @Data
 public class GradeRequestDTO {
 
-    /** ??? */
-    private final int userid;
-
-    /** ??? */
-    private final int courseid;
-
     /** ??? */
     private final int assignmentid;
 
diff --git a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/dto/UploadCredentialsDTO.java b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/dto/UploadCredentialsDTO.java
index e9e1970bd3d5331fe39742f70a6b51ed5463039f..a9a7a80f7337ba19f03077a2a5bfcc43b2d7d791 100644
--- a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/dto/UploadCredentialsDTO.java
+++ b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/dto/UploadCredentialsDTO.java
@@ -10,9 +10,6 @@ import lombok.Data;
 @Data
 public final class UploadCredentialsDTO {
 
-    /** ???? */
-    private final int courseid;
-
     private final int assignmentid;
 
     private final int assignctxid;
diff --git a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/service/IntegrityService.java b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/service/IntegrityService.java
new file mode 100644
index 0000000000000000000000000000000000000000..0eb6ff03794ec2085045ff5728c0db3cb84b02a8
--- /dev/null
+++ b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/service/IntegrityService.java
@@ -0,0 +1,83 @@
+package ch.epfl.cs107.grading.moodle.api.v1.service;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import java.security.NoSuchAlgorithmException;
+import java.util.Base64;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.Objects.isNull;
+
+/**
+ * Service to compute and check the HMAC of a request
+ *
+ * @author Hamza REMMAL (hamza.remmal@epfl.ch)
+ * @since 1.0
+ */
+@Service
+public final class IntegrityService {
+
+    /** Algorithm to use when hashing */
+    private static final String HMAC_ALGORITHM = "HmacSHA256";
+
+    private final Logger logger = LoggerFactory.getLogger(IntegrityService.class);
+
+    /** Randomly generated secret for hashing */
+    private static final SecretKey secret;
+
+    // HR : Generate the secret randomly
+    static {
+        try {
+            secret = KeyGenerator.getInstance(HMAC_ALGORITHM).generateKey();
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Generate the HMAC for a given submission ID and course ID
+     * @param id ID to hash
+     * @return the corresponding HMAC, null if the generation failed
+     */
+    public String generate(int id){
+        logger.info("Generating integrity HMAC for id {}", id);
+        // HR : Generate a unique string with both ids
+        var data = String.format("##%d##", id);
+        try {
+            var mac = Mac.getInstance(HMAC_ALGORITHM);
+            // HR : Initialize the MAC with the secret
+            mac.init(secret);
+            // HR : Append the data to the MAC
+            var macBytes = mac.doFinal(data.getBytes(UTF_8));
+            // HR : Return a base64 encoding of the MAC
+            return Base64.getEncoder().encodeToString(macBytes);
+        } catch (Exception e) {
+            logger.error("HMAC generation failed for request with id {}", id, e);
+            return null;
+        }
+    }
+
+    /**
+     * Check if the provided HMAC is valid
+     * @param hmac HMAC to verify
+     * @param id id to verify
+     * @return true if the HMAC is valid, false otherwise
+     */
+    public boolean check(String hmac, int id){
+        logger.info("Checking HMAC integrity for HMAC = {}", hmac);
+        var generated = generate(id);
+        if (isNull(generated)){
+            logger.error("Cannot verify HMAC = {} - HMAC generation failed", hmac);
+            return false;
+        } else {
+            logger.info("HMAC generation for verification was successful. Comparing both HMACs.");
+            return generated.equals(hmac);
+        }
+    }
+
+}
diff --git a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/service/KubernetesJobService.java b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/service/KubernetesService.java
similarity index 78%
rename from moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/service/KubernetesJobService.java
rename to moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/service/KubernetesService.java
index 2af62194da97bde5366308bda26ae58651a1b3fa..4ed67d31d877b64db9b41278654ad44e46a7f68a 100644
--- a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/service/KubernetesJobService.java
+++ b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/service/KubernetesService.java
@@ -20,62 +20,67 @@ import java.util.Optional;
 import java.util.UUID;
 
 /**
- * ???
+ * Service to communicate with the k8s cluster.
  *
  * @author Dixit Sabharwal (dixit.sabharwal@epfl.ch)
  * @author Hamza REMMAL (hamza.remmal@epfl.ch)
+ * @since 1.0
  */
 @Service
-public final class KubernetesJobService {
+public final class KubernetesService {
 
-    /**
-     * ???
-     */
-    private final Logger logger = LoggerFactory.getLogger(KubernetesJobService.class);
+    private final Logger logger = LoggerFactory.getLogger(KubernetesService.class);
 
-    /**
-     * ???
-     */
-    private final KubernetesClient kubernetesClient;
+    /** Client to communicate with the underlying k8s cluster */
+    private final KubernetesClient k8sClient;
 
-    /**
-     * ???
-     */
-    private final SubmissionIntegrityService subIntegrity;
+    /** Service to generate and check the integrity of the requests */
+    private final IntegrityService integrity;
+
+    /** URL to access the grading service itself */
+    private final String gradingServiceName;
 
-    @Value("${grading.service.name}")
-    private String gradingServiceName;
-    @Value("${server.port}")
-    private int gradingServicePort;
+    /** Port to access the grading service itself */
+    private final int gradingServicePort;
 
+    // TODO HR : This is not a 100% correct, we will have multiple namespaces (staging, production)
     private final String GRADING_SERVICE_NAMESPACE = "grading-service";
 
-    @Autowired
-    public KubernetesJobService(KubernetesClient kubernetesClient, SubmissionIntegrityService subIntegrity) {
-        this.kubernetesClient = kubernetesClient;
-        this.subIntegrity = subIntegrity;
+    /**
+     * @param k8sClient client to use to access the underlying k8s cluster
+     * @param integrity service to use for the integrity checks.
+     * @param serviceName URL to access the autograde-service itself
+     * @param servicePort Port to access the autograde-service itself
+     */
+    public KubernetesService(
+            @Autowired KubernetesClient k8sClient,
+            @Autowired IntegrityService integrity,
+            @Value("${grading.service.name}") String serviceName,
+            @Value("${server.port}") int servicePort) {
+        this.k8sClient = k8sClient;
+        this.integrity = integrity;
+        this.gradingServiceName = serviceName;
+        this.gradingServicePort = servicePort;
     }
 
     /**
      * ???
      *
-     * @param userid       ???
-     * @param courseid     ???
      * @param assignmentid ???
      * @param submissionid ???
      * @param imageName    ???
      * @return ???
      */
-    public String createJob(int userid, int courseid, int assignmentid, int submissionid, int assignctxid, String imageName)
+    public String createJob(int assignmentid, int submissionid, int assignctxid, String imageName)
             throws RuntimeException {
 
         // Generate the job name
         var jobName = generate_job_name();
 
         // Check if imagePullSecret exists
-        var imagePullSecret = getSecret(generate_imagePullSecret_name(courseid, assignmentid));
+        var imagePullSecret = getSecret(generate_imagePullSecret_name(assignmentid));
         if (imagePullSecret.isEmpty()) {
-            logger.error("ImagePullSecret for course {}, assignment {} does not exist. Tried using image {}.", courseid, assignmentid, imageName);
+            logger.error("ImagePullSecret for assignment {} does not exist. Tried using image {}.", assignmentid, imageName);
             throw new RuntimeException("Docker credentials do not exist.");
         }
 
@@ -83,21 +88,25 @@ public final class KubernetesJobService {
         var volume = prepare_job_volume(jobName);
 
         // Create an InitContainer to download the zip file into the ephemeral volume
-        var initContainer = prepare_init_container(volume, download_submission_command(courseid, submissionid, assignctxid));
+        var initContainer = prepare_init_container(volume, download_submission_command(submissionid, assignctxid));
         // Create container that will run the grading script
         var gradingContainer = prepare_grading_container(volume, imageName);
         // Create a ReportingContainer to report the grading results
-        var reportingContainer = prepare_feedback_container(volume, upload_feedback_command(userid, courseid, assignmentid, assignctxid, submissionid));
+        var reportingContainer = prepare_feedback_container(volume, upload_feedback_command(assignctxid, submissionid));
 
         // Define job
-        var job = create_job_object(jobName, volume, generate_imagePullSecret_name(courseid, submissionid),
-                initContainer, gradingContainer, reportingContainer,
-                userid, courseid, assignmentid, submissionid);
+        var job = create_job_object(jobName, volume, generate_imagePullSecret_name(submissionid),
+                initContainer, gradingContainer, reportingContainer, assignmentid, submissionid);
 
         // Create job
         try {
             logger.info("Creating job {}", jobName);
-            kubernetesClient.batch().v1().jobs().inNamespace(GRADING_SERVICE_NAMESPACE).resource(job).create();
+            k8sClient.batch()
+                    .v1()
+                    .jobs()
+                    .inNamespace(GRADING_SERVICE_NAMESPACE)
+                    .resource(job)
+                    .create();
         } catch (KubernetesClientException e) {
             logger.error("Failed to create job {}", jobName, e);
             throw new RuntimeException("Failed to create job");
@@ -109,7 +118,7 @@ public final class KubernetesJobService {
     private Optional<Secret> getSecret(String secretName) {
         Secret secret = null;
         try {
-            secret = kubernetesClient.secrets().inNamespace(GRADING_SERVICE_NAMESPACE).withName(secretName).get();
+            secret = k8sClient.secrets().inNamespace(GRADING_SERVICE_NAMESPACE).withName(secretName).get();
         } catch (KubernetesClientException e) {
             logger.error("Failed trying to read existing secret {}", secretName, e);
             throw new RuntimeException("Failed trying to read existing imagePullSecret");
@@ -117,8 +126,8 @@ public final class KubernetesJobService {
         return Optional.ofNullable(secret);
     }
 
-    public void tryCreateImagePullSecret(String dockerconfigjson, int courseid, int assignmentid) throws RuntimeException {
-        String secretName = generate_imagePullSecret_name(courseid, assignmentid);
+    public void tryCreateImagePullSecret(String dockerconfigjson, int assignmentid) throws RuntimeException {
+        String secretName = generate_imagePullSecret_name(assignmentid);
         String base64Dockerconfigjson = Base64.getEncoder().encodeToString(dockerconfigjson.getBytes());
 
         // Check if secret exists
@@ -132,7 +141,7 @@ public final class KubernetesJobService {
                 logger.info("Secret {} already exists but is different, deleting it", secretName);
                 try {
                     logger.info("Deleting secret {}", secretName);
-                    kubernetesClient.secrets().inNamespace(GRADING_SERVICE_NAMESPACE).withName(secretName).delete();
+                    k8sClient.secrets().inNamespace(GRADING_SERVICE_NAMESPACE).withName(secretName).delete();
                 } catch (KubernetesClientException e) {
                     logger.error("Failed to delete secret {}", secretName, e);
                     throw new RuntimeException("Failed to delete imagePullSecret");
@@ -155,7 +164,7 @@ public final class KubernetesJobService {
 
         try {
             logger.info("Creating secret {}", secretName);
-            kubernetesClient.secrets().inNamespace(GRADING_SERVICE_NAMESPACE).resource(regCred).create();
+            k8sClient.secrets().inNamespace(GRADING_SERVICE_NAMESPACE).resource(regCred).create();
         } catch (KubernetesClientException e) {
             logger.error("Failed to create secret {}", secretName, e);
             throw new RuntimeException("Failed to create imagePullSecret");
@@ -178,12 +187,11 @@ public final class KubernetesJobService {
     /**
      * ???
      *
-     * @param courseid     ???
      * @param assignmentid ???
      * @return ???
      */
-    private String generate_imagePullSecret_name(int courseid, int assignmentid) {
-        return String.format("regcred-%d-%d", courseid, assignmentid);
+    private String generate_imagePullSecret_name(int assignmentid) {
+        return String.format("regcred-%d", assignmentid);
     }
 
     /**
@@ -315,8 +323,6 @@ public final class KubernetesJobService {
      * @param initContainer      ???
      * @param gradingContainer   ???
      * @param reportingContainer ???
-     * @param userid             ???
-     * @param courseid           ???
      * @param assignmentid       ???
      * @param submissionid       ???
      * @return ???
@@ -324,7 +330,7 @@ public final class KubernetesJobService {
     private Job create_job_object(
             String job_name, Volume volume, String imagePullSecretRef,
             Container initContainer, Container gradingContainer, Container reportingContainer,
-            int userid, int courseid, int assignmentid, int submissionid
+            int assignmentid, int submissionid
     ) {
         return new JobBuilder()
                 .withApiVersion("batch/v1")
@@ -332,8 +338,6 @@ public final class KubernetesJobService {
                 .withMetadata(new ObjectMetaBuilder()
                         .withName(job_name)
                         .withLabels(Map.of(
-                                "userid", String.valueOf(userid),
-                                "courseid", String.valueOf(courseid),
                                 "assignmentid", String.valueOf(assignmentid),
                                 "submissionid", String.valueOf(submissionid)
                         ))
@@ -355,35 +359,31 @@ public final class KubernetesJobService {
     /**
      * ???
      *
-     * @param courseid     ???
      * @param submissionid ???
      * @return ???
      */
-    private String download_submission_command(int courseid, int submissionid, int assignctxid) {
-        var mac = URLEncoder.encode(subIntegrity.generate(courseid, submissionid), StandardCharsets.UTF_8);
+    private String download_submission_command(int submissionid, int assignctxid) {
+        var mac = URLEncoder.encode(integrity.generate(submissionid), StandardCharsets.UTF_8);
 
         return "curl -X GET -H \"API-KEY: $API_KEY\" " +
-                String.format("\"http://%s:%d/api/v1/submission/download?courseid=%d&submissionid=%d&assignctxid=%d&signature=%s\" ",
-                        gradingServiceName, gradingServicePort, courseid, submissionid, assignctxid, mac) +
+                String.format("\"http://%s:%d/api/v1/submission/download?submissionid=%d&assignctxid=%d&signature=%s\" ",
+                        gradingServiceName, gradingServicePort, submissionid, assignctxid, mac) +
                 "-o /data/submission.zip";
     }
 
     /**
      * ???
      *
-     * @param userid       ???
-     * @param courseid     ???
-     * @param assignmentid ???
      * @param submissionid ???
      * @return ???
      */
-    private String upload_feedback_command(int userid, int courseid, int assignmentid, int assignctx, int submissionid) {
-        var mac = URLEncoder.encode(subIntegrity.generate(courseid, submissionid), StandardCharsets.UTF_8);
+    private String upload_feedback_command(int assignctx, int submissionid) {
+        var mac = URLEncoder.encode(integrity.generate(submissionid), StandardCharsets.UTF_8);
 
         return "curl -X POST -H \"API-KEY: $API_KEY\" -H 'Content-Type: application/json' " +
                 "-d @/data/feedback.json " +
-                String.format("\"http://%s:%d/api/v1/grading/result?userid=%d&courseid=%d&assignmentid=%d&assignctxid=%d&submissionid=%d&signature=%s\"",
-                        gradingServiceName, gradingServicePort, userid, courseid, assignmentid, assignctx, submissionid, mac);
+                String.format("\"http://%s:%d/api/v1/feedback/upload?assignctxid=%d&submissionid=%d&signature=%s\"",
+                        gradingServiceName, gradingServicePort, assignctx, submissionid, mac);
     }
 
 }
\ No newline at end of file
diff --git a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/service/MoodleWebService.java b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/service/MoodleWebService.java
index 212107c6625efdb9ea2a318629443ddcacafdac2..9a82cd6dcf0cad026a903f89778039208ced6efc 100644
--- a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/service/MoodleWebService.java
+++ b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/service/MoodleWebService.java
@@ -26,28 +26,28 @@ import static java.net.http.HttpResponse.BodyHandlers.ofString;
 import static java.nio.charset.StandardCharsets.UTF_8;
 
 /**
- * ???
+ * Service to communicate with Moodle.
+ *
  * @author Hamza REMMAL (hamza.remmal@epfl.ch)
  * @since 1.0.0
  */
 @Service
 public final class MoodleWebService {
 
-    /** ??? */
+    private final Logger logger = LoggerFactory.getLogger(MoodleWebService.class);
+
+    /** Moodle's end-point to receive REST requests */
     private final static String MOODLE_WEB_SERVICE_API = "/webservice/rest/server.php";
 
-    /** ??? */
+    /** base URL of the Moodle instance to call */
     private final String MOODLE_BASE_URL;
 
-    /** ??? */
+    /** autograde Moodle's access token */
     private final String MOODLE_ACCESS_TOKEN;
 
-    private final Logger logger = LoggerFactory.getLogger(MoodleWebService.class);
-
     /**
-     * ???
-     * @param url ???
-     * @param token ???
+     * @param url URL of the Moodle instance to communicate with
+     * @param token autograde access token to the Moodle instance
      */
     public MoodleWebService(@Value("${moodle.baseurl}")String url, @Value("${moodle.autograde.token}") String token) {
         this.MOODLE_BASE_URL     = url;
@@ -96,11 +96,12 @@ public final class MoodleWebService {
         return client.send(request, handler);
     }
 
+    // ============================================================================================
+    // ================================== AUTOGRADE FUNCTIONS =====================================
+    // ============================================================================================
+
     /**
-     * ???
-     * @param userid ???
-     * @param courseid ???
-     * @param assignmentid ???
+     * Upload the feedback for an autograde compatible submission.
      * @param submissionid ???
      * @param grade ???
      * @param feedback ???
@@ -109,22 +110,13 @@ public final class MoodleWebService {
      * @throws IOException ???
      * @throws InterruptedException ???
      */
-    public HttpResponse<?> uploadAutoGradeFeedback(
-            int userid,
-            int courseid,
-            int assignmentid,
-            int assignctxid,
-            int submissionid,
-            int grade,
-            String feedback
-    ) throws URISyntaxException, IOException, InterruptedException {
+    public HttpResponse<?> upload_feedback(int assignctxid, int submissionid, int grade, String feedback) throws URISyntaxException, IOException, InterruptedException {
+        logger.info("Uploading feedback for submission with id {}", submissionid);
+
         final var FUNCTION_NAME = "mod_assignsubmission_autograde_upload_feedback";
 
         final var params = new HashMap<String, Object>();
         // HR : Build the parameters
-        params.put("userid", userid);
-        params.put("courseid", courseid);
-        params.put("assignmentid", assignmentid);
         params.put("assignctxid", assignctxid);
         params.put("submissionid", submissionid);
         params.put("grade", grade);
@@ -134,21 +126,19 @@ public final class MoodleWebService {
     }
 
     /**
-     * ???
-     * @param courseid ???
+     * Download an autograde compatible submission from Moodle
      * @param submissionid ???
      * @return ???
      * @throws URISyntaxException ???
      * @throws IOException ???
      * @throws InterruptedException ???
      */
-    public InputStream download_submission(int courseid, int submissionid, int assignctxid) throws URISyntaxException, IOException, InterruptedException {
-        logger.info("downloading submission {} in course {}", submissionid, courseid);
+    public InputStream download_submission(int submissionid, int assignctxid) throws URISyntaxException, IOException, InterruptedException {
+        logger.info("Downloading submission with id {} from Moodle ({})", submissionid, MOODLE_BASE_URL);
 
         final var FUNCTION_NAME = "mod_assignsubmission_autograde_download_submission";
 
         final var params = new HashMap<String, Object>();
-        params.put("courseid", courseid);
         params.put("submissionid", submissionid);
         params.put("assignctxid", assignctxid);
 
@@ -165,21 +155,19 @@ public final class MoodleWebService {
     }
 
     /**
-     * ???
-     * @param courseid ???
+     * Download the credentials for an autograde compatible assignment
      * @param assignmentid ???
      * @return ???
      * @throws URISyntaxException ???
      * @throws IOException ???
      * @throws InterruptedException ???
      */
-    public InputStream download_credentials(int courseid, int assignmentid, int assignctxid) throws URISyntaxException, IOException, InterruptedException {
-        logger.info("downloading credentials for assignment {} in course {}", assignmentid, courseid);
+    public InputStream download_credentials(int assignmentid, int assignctxid) throws URISyntaxException, IOException, InterruptedException {
+        logger.info("Downloading the credentials for assignment with id {}", assignmentid);
 
         final var FUNCTION_NAME = "mod_assignsubmission_autograde_download_credentials";
 
         final var params = new HashMap<String, Object>();
-        params.put("courseid", courseid);
         params.put("assignmentid", assignmentid);
         params.put("assignctxid", assignctxid);
 
diff --git a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/service/SubmissionIntegrityService.java b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/service/SubmissionIntegrityService.java
deleted file mode 100644
index 1fba9f63150938c06ad7e30def3e9fbfe38609fe..0000000000000000000000000000000000000000
--- a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/service/SubmissionIntegrityService.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package ch.epfl.cs107.grading.moodle.api.v1.service;
-
-import org.springframework.stereotype.Service;
-
-import javax.crypto.KeyGenerator;
-import javax.crypto.Mac;
-import javax.crypto.SecretKey;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.util.Base64;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-/**
- * ???
- *
- * @author Hamza REMMAL (hamza.remmal@epfl.ch)
- */
-@Service
-public final class SubmissionIntegrityService {
-
-    /** ??? */
-    private static final String HMAC_ALGORITHM = "HmacSHA256";
-
-    /** ??? */
-    private static final SecretKey secret;
-
-    static {
-        try {
-            secret = KeyGenerator.getInstance(HMAC_ALGORITHM).generateKey();
-        } catch (NoSuchAlgorithmException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * ???
-     * @param courseid ???
-     * @param submissionid ???
-     * @return ???
-     */
-    public String generate(int courseid, int submissionid){
-        // HR : Generate a unique string with both ids
-        var data = String.format("%d:%d", courseid, submissionid);
-        try {
-            var mac = Mac.getInstance(HMAC_ALGORITHM);
-            // HR : Initialize the MAC with the secret
-            mac.init(secret);
-            // HR : Append the data to the MAC
-            var macBytes = mac.doFinal(data.getBytes(UTF_8));
-            // HR : Return a base64 encoding of the MAC
-            return Base64.getEncoder().encodeToString(macBytes);
-        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * ???
-     * @param mac ???
-     * @param courseid ???
-     * @param submissionid ???
-     * @return ???
-     */
-    public boolean check(String mac, int courseid, int submissionid){
-        return generate(courseid, submissionid).equals(mac);
-    }
-
-}