diff --git a/ExpressAPI/assets/OpenAPI/OpenAPI.yaml b/ExpressAPI/assets/OpenAPI/OpenAPI.yaml
index 2bbe1d3a26375c79d0b02d84bb0773b74d13712c..b4d9846f36a75a1b46f1a023543eb92c7137588f 100644
--- a/ExpressAPI/assets/OpenAPI/OpenAPI.yaml
+++ b/ExpressAPI/assets/OpenAPI/OpenAPI.yaml
@@ -1,7 +1,7 @@
 openapi: 3.1.0
 info:
     title: Dojo API
-    version: 3.4.2
+    version: 3.5.0
     description: |
         **Backend API of the Dojo project.**
         
diff --git a/ExpressAPI/prisma/migrations/20240208132018_add_correction_to_assignment/migration.sql b/ExpressAPI/prisma/migrations/20240208132018_add_correction_to_assignment/migration.sql
new file mode 100644
index 0000000000000000000000000000000000000000..cf8fa0240acfd338b0414f0394685a96b8b2602b
--- /dev/null
+++ b/ExpressAPI/prisma/migrations/20240208132018_add_correction_to_assignment/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE `Exercise` ADD COLUMN `correctionCommit` JSON NULL;
diff --git a/ExpressAPI/prisma/schema.prisma b/ExpressAPI/prisma/schema.prisma
index a68226e0868e475d54557f330fa35699e2f34bf7..f60367392fbfdcdf104a78dea1e20a0101bdddb9 100644
--- a/ExpressAPI/prisma/schema.prisma
+++ b/ExpressAPI/prisma/schema.prisma
@@ -50,6 +50,8 @@ model Exercise {
     gitlabLastInfo     Json     @db.Json
     gitlabLastInfoDate DateTime
 
+    correctionCommit Json? @db.Json
+
     assignment Assignment @relation(fields: [assignmentName], references: [name], onDelete: NoAction, onUpdate: Cascade)
 
     members User[]
diff --git a/ExpressAPI/src/helpers/DatabaseHelper.ts b/ExpressAPI/src/helpers/DatabaseHelper.ts
index 89ec9c767cb8f879011a7f5e547eb1942657de7b..9dc14bb292ef7e2921617c135b1e4f8d014e2a78 100644
--- a/ExpressAPI/src/helpers/DatabaseHelper.ts
+++ b/ExpressAPI/src/helpers/DatabaseHelper.ts
@@ -1,7 +1,9 @@
-import { PrismaClient }    from '@prisma/client';
-import logger              from '../shared/logging/WinstonLogger';
-import UserQueryExtension  from './Prisma/Extensions/UserQueryExtension';
-import UserResultExtension from './Prisma/Extensions/UserResultExtension';
+import { PrismaClient }          from '@prisma/client';
+import logger                    from '../shared/logging/WinstonLogger';
+import UserQueryExtension        from './Prisma/Extensions/UserQueryExtension';
+import UserResultExtension       from './Prisma/Extensions/UserResultExtension';
+import AssignmentResultExtension from './Prisma/Extensions/AssignmentResultExtension';
+import ExerciseResultExtension   from './Prisma/Extensions/ExerciseResultExtension';
 
 
 const prisma = new PrismaClient({
@@ -29,7 +31,7 @@ prisma.$on('warn', e => logger.warn(`Prisma => ${ e.message }`));
 prisma.$on('error', e => logger.error(`Prisma => ${ e.message }`));
 
 
-const db = prisma.$extends(UserQueryExtension).$extends(UserResultExtension);
+const db = prisma.$extends(UserQueryExtension).$extends(UserResultExtension).$extends(AssignmentResultExtension).$extends(ExerciseResultExtension);
 
 
 export default db;
\ No newline at end of file
diff --git a/ExpressAPI/src/helpers/DojoValidators.ts b/ExpressAPI/src/helpers/DojoValidators.ts
index 98a28252c6bca786fe23ad6b08e56db54c33aca0..38465417c46274cff0e46ee3dbdc2929cb17f05b 100644
--- a/ExpressAPI/src/helpers/DojoValidators.ts
+++ b/ExpressAPI/src/helpers/DojoValidators.ts
@@ -7,6 +7,8 @@ import express                                                      from 'expres
 import logger                                                       from '../shared/logging/WinstonLogger';
 import Json5FileValidator                                           from '../shared/helpers/Json5FileValidator';
 import ExerciseResultsFile                                          from '../shared/types/Dojo/ExerciseResultsFile';
+import ParamsCallbackManager                                        from '../middlewares/ParamsCallbackManager';
+import ExerciseManager                                              from '../managers/ExerciseManager';
 
 
 declare type DojoMeta = Meta & {
@@ -106,6 +108,32 @@ class DojoValidators {
                                                                               });
                                                                           }
                                                                       });
+
+    readonly exerciseIdOrUrlValidator = this.toValidatorSchemaOptions({
+                                                                          bail        : true,
+                                                                          errorMessage: 'ExerciseIdOrUrl: not provided or invalid',
+                                                                          options     : (_value, {
+                                                                              req,
+                                                                              path
+                                                                          }) => {
+                                                                              return new Promise((resolve, reject) => {
+                                                                                  const exerciseIdOrUrl = this.getParamValue(req, path) as string;
+                                                                                  if ( exerciseIdOrUrl ) {
+                                                                                      ParamsCallbackManager.initBoundParams(req);
+
+                                                                                      ExerciseManager.get(exerciseIdOrUrl).then((exercise) => {
+                                                                                          req.boundParams.exercise = exercise;
+
+                                                                                          exercise !== undefined ? resolve(true) : reject();
+                                                                                      }).catch(() => {
+                                                                                          reject();
+                                                                                      });
+                                                                                  } else {
+                                                                                      reject();
+                                                                                  }
+                                                                              });
+                                                                          }
+                                                                      });
 }
 
 
diff --git a/ExpressAPI/src/helpers/Prisma/Extensions/AssignmentResultExtension.ts b/ExpressAPI/src/helpers/Prisma/Extensions/AssignmentResultExtension.ts
new file mode 100644
index 0000000000000000000000000000000000000000..56819c91d853807036d4848fd6b9fbefcc128792
--- /dev/null
+++ b/ExpressAPI/src/helpers/Prisma/Extensions/AssignmentResultExtension.ts
@@ -0,0 +1,36 @@
+import { Prisma }   from '@prisma/client';
+import { Exercise } from '../../../types/DatabaseTypes';
+import db           from '../../DatabaseHelper';
+import LazyVal      from '../../../shared/helpers/LazyVal';
+
+
+async function getCorrections(assignment: { name: string }): Promise<Array<Exercise> | undefined> {
+    try {
+        return await db.exercise.findMany({
+                                              where: {
+                                                  assignmentName  : assignment.name,
+                                                  correctionCommit: {
+                                                      not: Prisma.JsonNull
+                                                  }
+                                              }
+                                          }) as Array<Exercise> ?? undefined;
+    } catch ( e ) {
+        return undefined;
+    }
+}
+
+export default Prisma.defineExtension(client => {
+    return client.$extends({
+                               result: {
+                                   assignment: {
+                                       corrections: {
+                                           compute(assignment) {
+                                               return new LazyVal<Array<Exercise> | undefined>(() => {
+                                                   return getCorrections(assignment);
+                                               });
+                                           }
+                                       }
+                                   }
+                               }
+                           });
+});
\ No newline at end of file
diff --git a/ExpressAPI/src/helpers/Prisma/Extensions/ExerciseResultExtension.ts b/ExpressAPI/src/helpers/Prisma/Extensions/ExerciseResultExtension.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e11b4e247e78b59b49e0ebd52cb669857954d431
--- /dev/null
+++ b/ExpressAPI/src/helpers/Prisma/Extensions/ExerciseResultExtension.ts
@@ -0,0 +1,19 @@
+import { Prisma } from '@prisma/client';
+
+
+export default Prisma.defineExtension(client => {
+    return client.$extends({
+                               result: {
+                                   exercise: {
+                                       isCorrection: {
+                                           needs: {
+                                               correctionCommit: true
+                                           },
+                                           compute(exercise) {
+                                               return exercise.correctionCommit != null;
+                                           }
+                                       }
+                                   }
+                               }
+                           });
+});
\ No newline at end of file
diff --git a/ExpressAPI/src/managers/ExerciseManager.ts b/ExpressAPI/src/managers/ExerciseManager.ts
index 66cfda8a89bb8f8d726f03c54a2bdcf915b45914..720827d904b1332b90b632aa2ca965b23586b45f 100644
--- a/ExpressAPI/src/managers/ExerciseManager.ts
+++ b/ExpressAPI/src/managers/ExerciseManager.ts
@@ -4,7 +4,9 @@ import db           from '../helpers/DatabaseHelper';
 
 
 class ExerciseManager {
-    async get(id: string, include: Prisma.ExerciseInclude | undefined = undefined): Promise<Exercise | undefined> {
+    async get(idOrUrl: string, include: Prisma.ExerciseInclude | undefined = undefined): Promise<Exercise | undefined> {
+        const id = idOrUrl.replace('.git', '').split('_').pop()!;
+
         return await db.exercise.findUnique({
                                                 where  : {
                                                     id: id
diff --git a/ExpressAPI/src/managers/GitlabManager.ts b/ExpressAPI/src/managers/GitlabManager.ts
index 390fba57640e11b4514caa37df8131a4b9622886..3455f8b7accad04dc7c09ace93b1c297cb633d49 100644
--- a/ExpressAPI/src/managers/GitlabManager.ts
+++ b/ExpressAPI/src/managers/GitlabManager.ts
@@ -1,22 +1,29 @@
-import axios             from 'axios';
-import Config            from '../config/Config';
-import GitlabRepository  from '../shared/types/Gitlab/GitlabRepository';
-import GitlabAccessLevel from '../shared/types/Gitlab/GitlabAccessLevel';
-import GitlabMember      from '../shared/types/Gitlab/GitlabMember';
-import { StatusCodes }   from 'http-status-codes';
-import GitlabVisibility  from '../shared/types/Gitlab/GitlabVisibility';
-import GitlabUser        from '../shared/types/Gitlab/GitlabUser';
-import GitlabTreeFile    from '../shared/types/Gitlab/GitlabTreeFile';
-import parseLinkHeader   from 'parse-link-header';
-import GitlabFile        from '../shared/types/Gitlab/GitlabFile';
-import express           from 'express';
-import GitlabRoute       from '../shared/types/Gitlab/GitlabRoute';
-import SharedConfig      from '../shared/config/SharedConfig';
-import GitlabProfile     from '../shared/types/Gitlab/GitlabProfile';
-import GitlabRelease     from '../shared/types/Gitlab/GitlabRelease';
+import axios                    from 'axios';
+import Config                   from '../config/Config';
+import GitlabRepository         from '../shared/types/Gitlab/GitlabRepository';
+import GitlabAccessLevel        from '../shared/types/Gitlab/GitlabAccessLevel';
+import GitlabMember             from '../shared/types/Gitlab/GitlabMember';
+import { StatusCodes }          from 'http-status-codes';
+import GitlabVisibility         from '../shared/types/Gitlab/GitlabVisibility';
+import GitlabUser               from '../shared/types/Gitlab/GitlabUser';
+import GitlabTreeFile           from '../shared/types/Gitlab/GitlabTreeFile';
+import parseLinkHeader          from 'parse-link-header';
+import GitlabFile               from '../shared/types/Gitlab/GitlabFile';
+import express                  from 'express';
+import GitlabRoute              from '../shared/types/Gitlab/GitlabRoute';
+import SharedConfig             from '../shared/config/SharedConfig';
+import GitlabProfile            from '../shared/types/Gitlab/GitlabProfile';
+import GitlabRelease            from '../shared/types/Gitlab/GitlabRelease';
+import { CommitSchema, Gitlab } from '@gitbeaker/rest';
+import logger                   from '../shared/logging/WinstonLogger';
 
 
 class GitlabManager {
+    readonly api = new Gitlab({
+                                  host : SharedConfig.gitlab.URL,
+                                  token: Config.gitlab.account.token
+                              });
+
     private getApiUrl(route: GitlabRoute): string {
         return `${ SharedConfig.gitlab.apiURL }${ route }`;
     }
@@ -75,6 +82,21 @@ class GitlabManager {
         return response.data;
     }
 
+    async getRepositoryLastCommit(repoId: number, branch: string = 'main'): Promise<CommitSchema | undefined> {
+        try {
+            const commits = await this.api.Commits.all(repoId, {
+                refName : branch,
+                maxPages: 1,
+                perPage : 1
+            });
+
+            return commits.length > 0 ? commits[0] : undefined;
+        } catch ( e ) {
+            logger.error(e);
+            return undefined;
+        }
+    }
+
     async createRepository(name: string, description: string, visibility: string, initializeWithReadme: boolean, namespace: number, sharedRunnersEnabled: boolean, wikiEnabled: boolean, import_url: string): Promise<GitlabRepository> {
         const response = await axios.post<GitlabRepository>(this.getApiUrl(GitlabRoute.REPOSITORY_CREATE), {
             name                  : name,
diff --git a/ExpressAPI/src/middlewares/ParamsCallbackManager.ts b/ExpressAPI/src/middlewares/ParamsCallbackManager.ts
index cfcb275a4c3239e33f83fbb6360a10e31b5b0141..6dd5303a36e38091833b733472c0227733788ebe 100644
--- a/ExpressAPI/src/middlewares/ParamsCallbackManager.ts
+++ b/ExpressAPI/src/middlewares/ParamsCallbackManager.ts
@@ -39,7 +39,7 @@ class ParamsCallbackManager {
             staff    : true
         } ], 'assignment');
 
-        this.listenParam('exerciseId', backend, (ExerciseManager.get as GetFunction).bind(ExerciseManager), [ {
+        this.listenParam('exerciseIdOrUrl', backend, (ExerciseManager.get as GetFunction).bind(ExerciseManager), [ {
             assignment: true,
             members   : true,
             results   : true
diff --git a/ExpressAPI/src/routes/AssignmentRoutes.ts b/ExpressAPI/src/routes/AssignmentRoutes.ts
index ab2bd23456d446fd6a23a64e2bd9db7383b9b05c..c32ee2dfa6a061a997ca10a0067c592e9756814f 100644
--- a/ExpressAPI/src/routes/AssignmentRoutes.ts
+++ b/ExpressAPI/src/routes/AssignmentRoutes.ts
@@ -45,12 +45,23 @@ class AssignmentRoutes implements RoutesManager {
         }
     };
 
+    private readonly assignmentAddCorrigeValidator: ExpressValidator.Schema = {
+        exerciseIdOrUrl: {
+            trim    : true,
+            notEmpty: true,
+            custom  : DojoValidators.exerciseIdOrUrlValidator
+        }
+    };
+
     registerOnBackend(backend: Express) {
         backend.get('/assignments/:assignmentNameOrUrl', SecurityMiddleware.check(true), this.getAssignment.bind(this));
         backend.post('/assignments', SecurityMiddleware.check(true, SecurityCheckType.TEACHING_STAFF), ParamsValidatorMiddleware.validate(this.assignmentValidator), this.createAssignment.bind(this));
 
-        backend.patch('/assignments/:assignmentNameOrUrl/publish', SecurityMiddleware.check(true, SecurityCheckType.ASSIGNMENT_STAFF), this.publishAssignment.bind(this));
-        backend.patch('/assignments/:assignmentNameOrUrl/unpublish', SecurityMiddleware.check(true, SecurityCheckType.ASSIGNMENT_STAFF), this.unpublishAssignment.bind(this));
+        backend.patch('/assignments/:assignmentNameOrUrl/publish', SecurityMiddleware.check(true, SecurityCheckType.ASSIGNMENT_STAFF), this.changeAssignmentPublishedStatus(true).bind(this));
+        backend.patch('/assignments/:assignmentNameOrUrl/unpublish', SecurityMiddleware.check(true, SecurityCheckType.ASSIGNMENT_STAFF), this.changeAssignmentPublishedStatus(false).bind(this));
+
+        backend.post('/assignments/:assignmentNameOrUrl/corrections', SecurityMiddleware.check(true, SecurityCheckType.ASSIGNMENT_STAFF), ParamsValidatorMiddleware.validate(this.assignmentAddCorrigeValidator), this.addUpdateAssignmentCorrection(false).bind(this));
+        backend.patch('/assignments/:assignmentNameOrUrl/corrections/:exerciseIdOrUrl', SecurityMiddleware.check(true, SecurityCheckType.ASSIGNMENT_STAFF), this.addUpdateAssignmentCorrection(true).bind(this));
     }
 
     // Get an assignment by its name or gitlab url
@@ -171,14 +182,6 @@ class AssignmentRoutes implements RoutesManager {
         }
     }
 
-    private async publishAssignment(req: express.Request, res: express.Response) {
-        return this.changeAssignmentPublishedStatus(true)(req, res);
-    }
-
-    private async unpublishAssignment(req: express.Request, res: express.Response) {
-        return this.changeAssignmentPublishedStatus(false)(req, res);
-    }
-
     private changeAssignmentPublishedStatus(publish: boolean): (req: express.Request, res: express.Response) => Promise<void> {
         return async (req: express.Request, res: express.Response): Promise<void> => {
             if ( publish ) {
@@ -213,6 +216,39 @@ class AssignmentRoutes implements RoutesManager {
         };
     }
 
+    private addUpdateAssignmentCorrection(isUpdate: boolean): (req: express.Request, res: express.Response) => Promise<void> {
+        return async (req: express.Request, res: express.Response): Promise<void> => {
+            if ( req.boundParams.exercise?.assignmentName != req.boundParams.assignment?.name ) {
+                return req.session.sendResponse(res, StatusCodes.BAD_REQUEST, undefined, 'The exercise does not belong to the assignment', DojoStatusCode.ASSIGNMENT_EXERCISE_NOT_RELATED);
+            }
+
+            if ( !req.boundParams.assignment?.published ) {
+                return req.session.sendResponse(res, StatusCodes.BAD_REQUEST, undefined, 'The assignment must be public', DojoStatusCode.ASSIGNMENT_NOT_PUBLISHED);
+            }
+
+            if ( !isUpdate && req.boundParams.exercise?.isCorrection ) {
+                return req.session.sendResponse(res, StatusCodes.BAD_REQUEST, undefined, 'This exercise is already a correction', DojoStatusCode.EXERCISE_CORRECTION_ALREADY_EXIST);
+            } else if ( isUpdate && !req.boundParams.exercise?.isCorrection ) {
+                return req.session.sendResponse(res, StatusCodes.BAD_REQUEST, undefined, 'This exercise is not a correction', DojoStatusCode.EXERCISE_CORRECTION_NOT_EXIST);
+            }
+
+            const lastCommit = await GitlabManager.getRepositoryLastCommit(req.boundParams.assignment!.gitlabId);
+            if ( lastCommit ) {
+                await db.exercise.update({
+                                             where: {
+                                                 id: req.boundParams.exercise!.id
+                                             },
+                                             data : {
+                                                 correctionCommit: lastCommit
+                                             }
+                                         });
+
+                return req.session.sendResponse(res, StatusCodes.OK);
+            } else {
+                return req.session.sendResponse(res, StatusCodes.INTERNAL_SERVER_ERROR, undefined, 'No last commit found');
+            }
+        };
+    }
 }
 
 
diff --git a/ExpressAPI/src/routes/ExerciseRoutes.ts b/ExpressAPI/src/routes/ExerciseRoutes.ts
index 0642d3a99433e7d75432d573e8fda1f515f0b936..1317f5b40469d183c88323ee17cf2e5beab4176e 100644
--- a/ExpressAPI/src/routes/ExerciseRoutes.ts
+++ b/ExpressAPI/src/routes/ExerciseRoutes.ts
@@ -72,9 +72,9 @@ class ExerciseRoutes implements RoutesManager {
     registerOnBackend(backend: Express) {
         backend.post('/assignments/:assignmentNameOrUrl/exercises', SecurityMiddleware.check(true, SecurityCheckType.ASSIGNMENT_IS_PUBLISHED), ParamsValidatorMiddleware.validate(this.exerciseValidator), this.createExercise.bind(this));
 
-        backend.get('/exercises/:exerciseId/assignment', SecurityMiddleware.check(false, SecurityCheckType.EXERCISE_SECRET), this.getAssignment.bind(this));
+        backend.get('/exercises/:exerciseIdOrUrl/assignment', SecurityMiddleware.check(false, SecurityCheckType.EXERCISE_SECRET), this.getAssignment.bind(this));
 
-        backend.post('/exercises/:exerciseId/results', SecurityMiddleware.check(false, SecurityCheckType.EXERCISE_SECRET), ParamsValidatorMiddleware.validate(this.resultValidator), this.createResult.bind(this));
+        backend.post('/exercises/:exerciseIdOrUrl/results', SecurityMiddleware.check(false, SecurityCheckType.EXERCISE_SECRET), ParamsValidatorMiddleware.validate(this.resultValidator), this.createResult.bind(this));
     }
 
     private getExerciseName(assignment: Assignment, members: Array<GitlabUser>, suffix: number): string {
diff --git a/ExpressAPI/src/shared b/ExpressAPI/src/shared
index 75f67b647da34337f3b220cacf78b2115d6022bc..9e3f29d2f313ef96944a199da0db39f1827c496a 160000
--- a/ExpressAPI/src/shared
+++ b/ExpressAPI/src/shared
@@ -1 +1 @@
-Subproject commit 75f67b647da34337f3b220cacf78b2115d6022bc
+Subproject commit 9e3f29d2f313ef96944a199da0db39f1827c496a
diff --git a/ExpressAPI/src/types/DatabaseTypes.ts b/ExpressAPI/src/types/DatabaseTypes.ts
index 632b05be5eda9eebf30a8c392e5a4020292dd10d..ae95e3bfb03a2b7c52dab17b486f36439ae139f6 100644
--- a/ExpressAPI/src/types/DatabaseTypes.ts
+++ b/ExpressAPI/src/types/DatabaseTypes.ts
@@ -31,6 +31,10 @@ export type User = Prisma.UserGetPayload<typeof userBase> & {
     isAdmin: boolean
     gitlabProfile: LazyVal<GitlabUser>
 }
-export type Assignment = Prisma.AssignmentGetPayload<typeof assignmentBase>
-export type Exercise = Prisma.ExerciseGetPayload<typeof exerciseBase>
+export type Exercise = Prisma.ExerciseGetPayload<typeof exerciseBase> & {
+    isCorrection: boolean
+}
+export type Assignment = Prisma.AssignmentGetPayload<typeof assignmentBase> & {
+    corrections: LazyVal<Exercise>
+}
 export type Result = Prisma.ResultGetPayload<typeof resultBase>
\ No newline at end of file