diff --git a/.gitignore b/.gitignore
index e4e5ae6d7f354cafe33fd718c282e738d8a49b31..115e10fd00b924aa8a3c09305afe7b64f58fca24 100644
--- a/.gitignore
+++ b/.gitignore
@@ -105,3 +105,6 @@ dist
 
 # config files
 config.json
+
+# file where we store pdf
+files/*
diff --git a/package-lock.json b/package-lock.json
index 281e305b46292835dd3dd5c94dce59946bb73a23..401ac877b7e04bd6d678617cb537babf644273c9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -20,6 +20,7 @@
         "eslint-import-resolver-typescript": "^3.5.2",
         "fastify": "^4.9.2",
         "mongoose": "^6.7.2",
+        "multer": "^1.4.5-lts.1",
         "passport": "^0.6.0",
         "passport-jwt": "^4.0.0",
         "passport-local": "^1.0.0",
@@ -37,6 +38,7 @@
         "@types/passport-jwt": "^3.0.8",
         "@types/passport-local": "^1.0.34",
         "@types/supertest": "^2.0.11",
+        "@types/uuid": "^9.0.0",
         "@typescript-eslint/eslint-plugin": "^5.0.0",
         "@typescript-eslint/parser": "^5.0.0",
         "cross-env": "^7.0.3",
@@ -2683,6 +2685,23 @@
         "@nestjs/core": "^9.0.0"
       }
     },
+    "node_modules/@nestjs/platform-express/node_modules/multer": {
+      "version": "1.4.4-lts.1",
+      "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4-lts.1.tgz",
+      "integrity": "sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==",
+      "dependencies": {
+        "append-field": "^1.0.0",
+        "busboy": "^1.0.0",
+        "concat-stream": "^1.5.2",
+        "mkdirp": "^0.5.4",
+        "object-assign": "^4.1.1",
+        "type-is": "^1.6.4",
+        "xtend": "^4.0.0"
+      },
+      "engines": {
+        "node": ">= 6.0.0"
+      }
+    },
     "node_modules/@nestjs/schematics": {
       "version": "9.0.3",
       "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-9.0.3.tgz",
@@ -3232,6 +3251,12 @@
         "@types/superagent": "*"
       }
     },
+    "node_modules/@types/uuid": {
+      "version": "9.0.0",
+      "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.0.tgz",
+      "integrity": "sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==",
+      "dev": true
+    },
     "node_modules/@types/webidl-conversions": {
       "version": "7.0.0",
       "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
@@ -8255,9 +8280,9 @@
       "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
     },
     "node_modules/multer": {
-      "version": "1.4.4-lts.1",
-      "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4-lts.1.tgz",
-      "integrity": "sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==",
+      "version": "1.4.5-lts.1",
+      "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz",
+      "integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==",
       "dependencies": {
         "append-field": "^1.0.0",
         "busboy": "^1.0.0",
@@ -12979,6 +13004,22 @@
         "express": "4.18.2",
         "multer": "1.4.4-lts.1",
         "tslib": "2.4.1"
+      },
+      "dependencies": {
+        "multer": {
+          "version": "1.4.4-lts.1",
+          "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4-lts.1.tgz",
+          "integrity": "sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==",
+          "requires": {
+            "append-field": "^1.0.0",
+            "busboy": "^1.0.0",
+            "concat-stream": "^1.5.2",
+            "mkdirp": "^0.5.4",
+            "object-assign": "^4.1.1",
+            "type-is": "^1.6.4",
+            "xtend": "^4.0.0"
+          }
+        }
       }
     },
     "@nestjs/schematics": {
@@ -13468,6 +13509,12 @@
         "@types/superagent": "*"
       }
     },
+    "@types/uuid": {
+      "version": "9.0.0",
+      "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.0.tgz",
+      "integrity": "sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==",
+      "dev": true
+    },
     "@types/webidl-conversions": {
       "version": "7.0.0",
       "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
@@ -17223,9 +17270,9 @@
       "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
     },
     "multer": {
-      "version": "1.4.4-lts.1",
-      "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4-lts.1.tgz",
-      "integrity": "sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==",
+      "version": "1.4.5-lts.1",
+      "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz",
+      "integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==",
       "requires": {
         "append-field": "^1.0.0",
         "busboy": "^1.0.0",
diff --git a/package.json b/package.json
index ce7cb37cf1166ee2c63ff9e6c7f8888476489125..59ed794c5e0baad88e3a45216060b8d0673b9a10 100644
--- a/package.json
+++ b/package.json
@@ -36,6 +36,7 @@
     "eslint-import-resolver-typescript": "^3.5.2",
     "fastify": "^4.9.2",
     "mongoose": "^6.7.2",
+    "multer": "^1.4.5-lts.1",
     "passport": "^0.6.0",
     "passport-jwt": "^4.0.0",
     "passport-local": "^1.0.0",
@@ -53,6 +54,7 @@
     "@types/passport-jwt": "^3.0.8",
     "@types/passport-local": "^1.0.34",
     "@types/supertest": "^2.0.11",
+    "@types/uuid": "^9.0.0",
     "@typescript-eslint/eslint-plugin": "^5.0.0",
     "@typescript-eslint/parser": "^5.0.0",
     "cross-env": "^7.0.3",
diff --git a/src/app.module.ts b/src/app.module.ts
index b0ed19151deea8f71a8695e2c3ae05f300f3642f..2c246c578f6188c5bfe8d3ad493285dab30f8d95 100644
--- a/src/app.module.ts
+++ b/src/app.module.ts
@@ -5,12 +5,14 @@ import { PeopleModule } from './people/people.module';
 import { GroupsModule } from './groups/groups.module';
 import { LoginModule } from './login/login.module';
 import { InternshipsModule } from './internships/internships.module';
+import { ResourcesModule } from './resources/resources.module';
 
 @Module({
   imports: [
     PeopleModule,
     GroupsModule,
     InternshipsModule,
+    ResourcesModule,
     MongooseModule.forRoot(config.mongodb.uri),
     LoginModule
   ],
diff --git a/src/config/config.model.ts b/src/config/config.model.ts
index 79984c4772b4ffd39b85c626dd4b79773b210239..b89c81748bf1996838ee041549c23b0c9ef654e9 100644
--- a/src/config/config.model.ts
+++ b/src/config/config.model.ts
@@ -1,12 +1,19 @@
-export interface IServerConfig {
+interface IServerConfig {
+  uri: string;
   port: number;
 }
 
-export interface IMongodbConfig {
+interface IResources {
+  root: string;
+  agreements: string;
+}
+
+interface IMongodbConfig {
   uri: string;
 }
 
 export interface IConfig {
   server: IServerConfig;
+  resources: IResources;
   mongodb: IMongodbConfig;
 }
diff --git a/src/config/config.prod.json b/src/config/config.prod.json
index 221da47e94f8ee7466bfef5535006d094832ff04..68a5550e9693089ed1d786acbcdeb74187f39d96 100644
--- a/src/config/config.prod.json
+++ b/src/config/config.prod.json
@@ -3,6 +3,9 @@
     "uri": "localhost",
     "port": 3001
   },
+  "resources": {
+    "internshipAgreements": "internship-agreements"
+  },
   "mongodb": {
     "uri": "mongodb://localhost:27017/internship-manager"
   }
diff --git a/src/config/config.template.json b/src/config/config.template.json
index ee6bb8331d52b839ede08f6ab08f39349591a7f5..68a5550e9693089ed1d786acbcdeb74187f39d96 100644
--- a/src/config/config.template.json
+++ b/src/config/config.template.json
@@ -1,7 +1,11 @@
 {
   "server": {
+    "uri": "localhost",
     "port": 3001
   },
+  "resources": {
+    "internshipAgreements": "internship-agreements"
+  },
   "mongodb": {
     "uri": "mongodb://localhost:27017/internship-manager"
   }
diff --git a/src/config/index.ts b/src/config/index.ts
index e948aaeb8cdb7af0e37d8b5ec06c5e704881c2c0..70281753480b8a73a4f2d8404d9f1d42c846f961 100644
--- a/src/config/index.ts
+++ b/src/config/index.ts
@@ -7,7 +7,8 @@ import { exit } from 'process';
 const CONFIG_DEV = 'config.json';
 const CONFIG_PROD = 'config.prod.json';
 
-let config;
+let config: IConfig;
+console.log(process.env.NODE_ENV);
 // Load config based on env
 switch (process.env.NODE_ENV) {
   case 'dev':
@@ -30,5 +31,7 @@ switch (process.env.NODE_ENV) {
     exit(-1);
 }
 
+console.log(config);
+
 // Export config
 export default config;
diff --git a/src/internships/dao/internships.dao.ts b/src/internships/dao/internships.dao.ts
index b5bfdfc5babc8139f359b4db96dd05c6e8545377..22a08178f9e288cc68691af8cf6e3a570ea36dfa 100644
--- a/src/internships/dao/internships.dao.ts
+++ b/src/internships/dao/internships.dao.ts
@@ -120,8 +120,9 @@ export class InternshipDao {
     content: string | boolean,
   ): Promise<Internship | void> =>
     new Promise((resolve, reject) => {
+      console.log('%s/%s: {%s}', studentId, state, content);
       if (!isStateValid(state)) reject(BAD_REQUEST);
-      console.log(typeof content);
+      console.log(content);
       let nextState: string, contentHolder: string;
       let valid = false;
       switch (state) {
diff --git a/src/internships/internships.controller.ts b/src/internships/internships.controller.ts
index 1fb011eb7d7a98fa8e58cf5981bf003c48d7033a..3db74f04f2bddd9213935ca4e5cde9c0590260e7 100644
--- a/src/internships/internships.controller.ts
+++ b/src/internships/internships.controller.ts
@@ -7,13 +7,23 @@ import {
   Param,
   Body,
   UseInterceptors,
+  UploadedFile,
 } from '@nestjs/common';
-import { BAD_TRACKING_STATE } from 'src/shared/HttpError';
+import { BAD_REQUEST, BAD_TRACKING_STATE } from 'src/shared/HttpError';
 import * as InternshipStates from 'src/shared/InternshipState';
 import { HttpInterceptor } from '../interceptors/http.interceptor';
 import { CreateInternshipDto } from './dto/create-internship.dto';
 import { InternshipEntity } from './entities/internship.entity';
 import { InternshipService } from './internships.service';
+import { FileInterceptor } from '@nestjs/platform-express';
+import {
+  STATE_RESPONSIBLE_ACCEPTS_INTERNSHIP_INFORMATION,
+  STATE_STUDENT_ENTERS_INTERNSHIP_INFORMATION,
+} from 'src/shared/InternshipState';
+import config from 'src/config';
+import { Optional } from '@nestjs/common/decorators';
+import { v4 } from 'uuid';
+import { diskStorage } from 'multer';
 
 @Controller('internships')
 @UseInterceptors(HttpInterceptor)
@@ -47,18 +57,43 @@ export class InternshipsController {
     return this._internshipsService.update(params.studentId, internshipDto);
   }
 
-  @Put(':studentId/tracking')
+  // uploads even if invalid state...
+  @Put(':studentId/:state')
+  @UseInterceptors(
+    FileInterceptor('pdf', {
+      storage: diskStorage({
+        destination: './files',
+        filename: (_req, _file, cb) => {
+          return cb(null, `${v4()}.pdf`);
+        },
+      }),
+    }),
+  )
   updateState(
-    @Param() params: { studentId: string },
-    @Body() body: { state: string; content?: string | boolean },
+    @Param() params: { studentId: string; state: string },
+    @Optional() @Body() body: { content?: boolean },
+    @Optional() @UploadedFile() file,
   ): Promise<InternshipEntity | void> {
-    if (!InternshipStates.isStateValid(body.state))
-      throw BAD_TRACKING_STATE(body.state);
-    // AMINE : Handle PDF file upload -> save file in /pdf/ folder and set content as local file URL. In case of step with no file, set content as true/false
+    if (!InternshipStates.isStateValid(params.state))
+      throw BAD_TRACKING_STATE(params.state);
+    if (
+      params.state === STATE_STUDENT_ENTERS_INTERNSHIP_INFORMATION ||
+      params.state === STATE_RESPONSIBLE_ACCEPTS_INTERNSHIP_INFORMATION
+    ) {
+      if (!body) throw BAD_REQUEST;
+      return this._internshipsService.updateTracking(
+        params.studentId,
+        params.state,
+        body.content,
+      );
+    }
+
+    if (!file) throw BAD_REQUEST;
+    console.log(params.state);
     return this._internshipsService.updateTracking(
       params.studentId,
-      body.state,
-      body.content,
+      params.state,
+      `${config.server.uri}:${config.server.port}/resources/agreements/${file.filename}`,
     );
   }
 
diff --git a/src/main.ts b/src/main.ts
index c5c630c00749273794025342b1f60b6be049f12f..bffb6eaf43e8ba958fa978ecfa619bb646febfac 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -1,7 +1,7 @@
+import config from './config';
 import { ValidationPipe } from '@nestjs/common';
 import { NestFactory } from '@nestjs/core';
 import { AppModule } from './app.module';
-import config from './config';
 
 async function bootstrap() {
   const env = process.env.NODE_ENV;
diff --git a/src/resources/resources.controller.ts b/src/resources/resources.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..afd5df97a65ed6741e182a9a5984392acaa1bf95
--- /dev/null
+++ b/src/resources/resources.controller.ts
@@ -0,0 +1,31 @@
+import {
+  Controller,
+  Get,
+  Param,
+  UseInterceptors,
+  Res,
+  StreamableFile,
+} from '@nestjs/common';
+import { NOT_FOUND } from 'src/shared/HttpError';
+import { HttpInterceptor } from '../interceptors/http.interceptor';
+import { Response } from 'express';
+import { createReadStream, existsSync } from 'fs';
+
+@Controller('resources')
+@UseInterceptors(HttpInterceptor)
+export class ResourcesController {
+  @Get('agreements/:filename')
+  serveAgreement(
+    @Param('filename') filename,
+    @Res({ passthrough: true }) res: Response,
+  ): StreamableFile {
+    const filepath = `files\\${filename}`;
+    if (!existsSync(filepath)) throw NOT_FOUND;
+    const file = createReadStream(filepath);
+    res.set({
+      'Content-Type': 'application/pdf',
+      'Content-Disposition': 'attachment; filename="agreement.pdf"',
+    });
+    return new StreamableFile(file);
+  }
+}
diff --git a/src/resources/resources.module.ts b/src/resources/resources.module.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6cadff34ed1d90667bb42bdb003a39f3d876748b
--- /dev/null
+++ b/src/resources/resources.module.ts
@@ -0,0 +1,8 @@
+import { Module, Logger } from '@nestjs/common';
+import { ResourcesController } from './resources.controller';
+
+@Module({
+  controllers: [ResourcesController],
+  providers: [Logger],
+})
+export class ResourcesModule {}
diff --git a/src/shared/HttpError.ts b/src/shared/HttpError.ts
index aa1d3565c01e62554e91ff4537c67ecc952ff961..200448b6f55e01865f8f8350e4fdb9dfcfcfc028 100644
--- a/src/shared/HttpError.ts
+++ b/src/shared/HttpError.ts
@@ -11,6 +11,7 @@ export const NOT_FOUND = new NotFoundException();
 export const CONFLICT = new ConflictException();
 export const BAD_REQUEST = new BadRequestException();
 export const INTERNAL = new InternalServerErrorException();
+export const UNPROCESSABLE_ENTITY = new UnprocessableEntityException();
 export const BAD_TRACKING_STATE = (badState: string) =>
   new UnprocessableEntityException(`Unknown state [${badState}]`);
 export const CUSTOM = (reason: string, errorStatus: number) =>