diff --git a/client/src/App.vue b/client/src/App.vue
index c51a8c81fc1ebba3407ff06243f0938b4404654d..e7bc8625c14e748ed4fc45af427807c686f190e1 100644
--- a/client/src/App.vue
+++ b/client/src/App.vue
@@ -18,22 +18,17 @@
         </div>
         <div id="navMenu" class="navbar-menu" :class="{ 'is-active': showNav }">
           <div class="navbar-start">
-            <a v-if="$store.state.isLoggedIn" class="navbar-item"
+            <a class="navbar-item"
               ><router-link to="/results"
                 ><i class="fas fa-flag-checkered" /> Enregistrer des résultats</router-link
               ></a
             >
-            <a class="navbar-item"
+            <!--a class="navbar-item"
               ><router-link to="/encoder"
                 ><i class="fas fa-code" /> Encodeur NFC</router-link
               ></a
-            >
-            <a class="navbar-item"
-              ><router-link to="/legal"
-                ><i class="fas fa-balance-scale" /> Mentions
-                légales</router-link
-              ></a
-            >
+            -->
+            
             <a v-if="$store.state.isLoggedIn" class="navbar-item"
               ><router-link to="/school"
                 ><i class="fas fa-school" /> Mon établissement ({{
@@ -41,6 +36,12 @@
                 }})</router-link
               ></a
             >
+            <a class="navbar-item"
+              ><router-link to="/legal"
+                ><i class="fas fa-balance-scale" /> Mentions
+                légales</router-link
+              ></a
+            >
           </div>
           <div class="navbar-end">
             
@@ -99,7 +100,8 @@ export default {
     this.usbNfcReader = new UsbNfcReader();
   },
   mounted() {
-    let uri = "//localhost:3000/loginCheck";
+    var domainName = '//'+location.hostname+(location.port ? ':'+location.port: '');
+    let uri = domainName + "/loginCheck";
     this.axios.post(uri, {}, { withCredentials: true }).then(response => {
         console.log(response);
         if (response.data != "ok")
@@ -108,12 +110,13 @@ export default {
     setTimeout(() => this.checkNfcModule(), 1000)
     setInterval(() => {
       this.checkNfcModule()
-    }, 50000)
+    }, 2500)
       
   },
   methods: {
     logout() {
-      let uri = "//localhost:3000/logout";
+      var domainName = '//'+location.hostname+(location.port ? ':'+location.port: '');
+      let uri = domainName + "/logout";
       this.axios.post(uri, {}, { withCredentials: true }).then(response => {
         console.log(response);
         this.$store.commit("logout");
@@ -121,11 +124,11 @@ export default {
     },
     connectUsb() {
       this.usbNfcReader.selectAndConnect()
-      this.setTimeout(() => this.checkNfcModule(), 1000);
+      this.setTimeout(() => this.checkNfcModule(), 500);
     },
     disconnectUsb() {
       this.usbNfcReader.disconnect()
-      this.setTimeout(() => this.checkNfcModule(), 1000);
+      this.setTimeout(() => this.checkNfcModule(), 500);
     },
     checkNfcModule() {
       this.usbNfcReader.ping().then(() => {
diff --git a/client/src/components/Login.vue b/client/src/components/Login.vue
index 31f49fec39600f0f5fb2a58148e94ec00c5e43f9..dd49578c2def324b05a8b01a1b21973ad6fb6e5a 100644
--- a/client/src/components/Login.vue
+++ b/client/src/components/Login.vue
@@ -47,7 +47,8 @@ export default {
   },
   methods: {
     login() {
-      let uri = "//localhost:3000/login";
+      var domainName = '//'+location.hostname+(location.port ? ':'+location.port: '');
+      let uri = domainName + "/login";
       this.axios
         .post(
           uri,
diff --git a/client/src/components/PageFooter.vue b/client/src/components/PageFooter.vue
index cf1150e92d3e0b55e4d135d4d06de132cedf3507..75263bf39984e9cdb7984084ee2a2e8f77b19968 100644
--- a/client/src/components/PageFooter.vue
+++ b/client/src/components/PageFooter.vue
@@ -14,7 +14,7 @@
     <div class="content">
       <p>
         Conçu et développé par les associations Clubelek et Objectif21, de
-        l'INSA Lyon - Saison 2020/2021
+        l'INSA Lyon - Saison 2020/2021 - Made with 💚 by Antoine Rochebois
       </p>
     </div>
   </footer>
diff --git a/client/src/components/Register.vue b/client/src/components/Register.vue
index c8248f39e3070810ec5d9285336fd73ce37c3c25..36da9f1a869fce23a6012b8980945bf9f0d29651 100644
--- a/client/src/components/Register.vue
+++ b/client/src/components/Register.vue
@@ -62,7 +62,8 @@ export default {
   },
   methods: {
     register() {
-      let uri = "//localhost:3000/register";
+      var domainName = '//'+location.hostname+(location.port ? ':'+location.port: '');
+      let uri = domainName + "/register";
       this.axios
         .post(
           uri,
diff --git a/client/src/components/ResultsDisplay.vue b/client/src/components/ResultsDisplay.vue
index 85dbb58e338e1606abf5ddb77f4e2c97c7f2aa21..667d03eecec112c3fe39d74e9a47c605dfd5dd6c 100644
--- a/client/src/components/ResultsDisplay.vue
+++ b/client/src/components/ResultsDisplay.vue
@@ -1,8 +1,14 @@
 <template>
   <div class="content">
-    <article v-if="this.team.name.length > 0" class="message is-info">
+    <div v-if="globalScore >= 0" class="has-text-centered">
+      <p class = "is-size-4 m-0">Score total :</p>
+      <p class = "is-size-1 m-0" style="color:green;">🔥  {{globalScore}}  🔥</p>
+      <p class = "is-size-3 mb-6">🥳  Félicitations ! 🥳</p>
+    </div>
+
+    <article v-if="this.team.name.length > 0" class="message is-success">
       <div class="message-header">
-        Résultats de l'équipe {{ team.name }} ({{ memberCount }} membres)
+        🏁 Résultats de l'équipe "{{ team.name }}" ({{ memberCount }} membres) 🏁
       </div>
       <div class="message-body">
         <div>
@@ -52,9 +58,9 @@
         </div>
       </div>
     </article>
-    <article v-else>
-      <p>Merci de scanner une carte d'équipe pour afficher et enregistrer des résultats</p>
-      <button class="button is-primary" @click="showPairingModal = !showPairingModal"><i class="fas fa-download"></i> Scanner la carte de l'équipe !</button>
+    <article class="container has-text-centered">
+      <p class="is-size-4">🏁  Merci de scanner une carte d'équipe pour afficher et enregistrer des résultats  🏁</p>
+      <button class="button is-primary is-large is-fullwidth" @click="manageCardReading()"><i class="fas fa-download"></i> Scanner la carte de l'équipe !</button>
     </article>
 
     <div class="modal" :class="{ 'is-active': showPairingModal }">
@@ -80,13 +86,16 @@
 </template>
 
 <script>
+import puzzleJson from '../puzzles.json'
 export default {
   name: "ResultDisplay",
 
   data() {
     return {
       showPairingModal: false,
-      team : { name: "", members: [], donePuzzles : [] }
+      puzzles: puzzleJson,
+      team : { name: "", members: [], donePuzzles : [] },
+      globalScore: -1
     };
   },
 
@@ -97,6 +106,54 @@ export default {
   },
 
   methods: {
+    manageCardReading() {
+      this.showPairingModal = true;
+      this.$parent.usbNfcReader.readCard().then(cardContent=> {
+        this.$parent.usbNfcReader.readTagUid().then(tagUid => {
+          this.team = { name: "", members: [], donePuzzles : [] }
+          let resultsStr = cardContent.split(';')
+          resultsStr.shift()
+          resultsStr.pop()
+          if (resultsStr.length == 0) {
+            console.log("Carte vierge de toute épreuve !")
+            return;
+          }
+          resultsStr.forEach(resultStr => {
+            let resShort = resultStr.split('_')[0]
+            let score = resultStr.split('_')[1]
+            let puzzle = this.puzzles[resShort]
+            var donePuzzle = {name: puzzle.name, room:puzzle.room, coef:puzzle.coef}
+            if (puzzle.type == "boolean") {
+              if (score >= 1) donePuzzle.validated = true;
+              else donePuzzle.validated = false;
+            } else if (puzzle.type == "number") {
+              donePuzzle.maxScore = puzzle.maxScore;
+              donePuzzle.score = score
+            }
+            this.team.donePuzzles.push(donePuzzle)
+          });
+          console.log(this.team.donePuzzles)
+          var domainName = '//'+location.hostname+(location.port ? ':'+location.port: '');
+          let uri = domainName + "/school/updateTeamPuzzles/" + tagUid;
+          let uriGet = domainName + "/school/getTeamByCardID/" + tagUid;
+          this.axios.post(uri, this.team.donePuzzles, { withCredentials: true }).then(() => {
+            console.log("Score ajouté à la BD !");
+            this.axios.get(uriGet, { withCredentials: true }).then((response) => {
+              this.team = response.data[0]
+              this.globalScore = 0
+              this.team.donePuzzles.forEach(puzzle => {
+                if (puzzle.score)
+                  this.globalScore += parseInt(puzzle.coef)*parseInt(puzzle.score)
+                else if (puzzle.validated)
+                this.globalScore += parseInt(puzzle.coef)
+                
+              });
+              this.showPairingModal = false
+            });
+          });
+        });
+      });
+    }
   }
 };
 </script>
diff --git a/client/src/components/SchoolManager.vue b/client/src/components/SchoolManager.vue
index 643f521799c2db320f14c90e3b2119fd70ff1324..6f3b6fead9e76bfedd8b65a89017e745affdf32f 100644
--- a/client/src/components/SchoolManager.vue
+++ b/client/src/components/SchoolManager.vue
@@ -1,16 +1,48 @@
 <template>
   <div id="app" class="content">
-    <div class="message is-medium">
-      <div class="message-header">Mes équipes</div>
-      <div class="message-body">
-        <div @addedTeam="updateTeams" v-for="team in teams" :key="team._id">
+
+        <div v-if="teams[0].donePuzzles.length > 0" class="container mb-6 has-text-centered">
+          <p class="is-size-3">🏅  Classement des équipes  🏅</p>
+
+          <div v-for="(team, index) in teams" :key="team._id" >
+            <div v-if="team.donePuzzles">
+              <div v-if="team.donePuzzles.length > 0" class="box mb-2">
+                <nav class="level">
+                  <div class="level-item has-text-centered">
+                    <div>
+                      <p class="heading">Rang</p>
+                      <p v-if="index==0" class="title">🥇</p>
+                      <p v-else-if="index==1" class="title">🥈</p>
+                      <p v-else-if="index==2" class="title">🥉</p>
+                      <p v-else class="title">{{index+1}}</p>
+                    </div>
+                  </div>
+                  <div class="level-item has-text-centered">
+                    <div>
+                      <p class="heading">équipe</p>
+                      <p class="title">{{team.name}}</p>
+                    </div>
+                  </div>
+                  <div class="level-item has-text-centered">
+                    <div>
+                      <p class="heading">Score</p>
+                      <p class="title">{{getGlobalScore(team)}}</p>
+                    </div>
+                  </div>
+                </nav>
+              </div>
+            </div>
+          </div>
+        </div>
+
+
+        <div class="mb-2" @addedTeam="updateTeams" v-for="team in teams" :key="team._id">
           <TeamElement :team="team" :teamArray="teams" />
         </div>
-        <TeamAdder :teamArray="teams"></TeamAdder>
+
+
+        <TeamAdder class="mt-6" :teamArray="teams"></TeamAdder>
       </div>
-    </div>
-    
-  </div>
 </template>
 
 <script>
@@ -29,19 +61,42 @@ export default {
     };
   },
   created() {
-    let uri = "//localhost:3000/school";
+    
+  },
+
+  mounted() {
+    var domainName = '//'+location.hostname+(location.port ? ':'+location.port: '');
+    let uri = domainName + "/school";
     this.axios.get(uri, { withCredentials: true }).then(response => {
       this.teams = response.data;
+      this.sortTeams()
       console.log(response);
     });
-  },
 
-  mounted() {},
+  },
   methods: {
     updateTeams(teams) {
       this.teams = teams;
+      this.sortTeams()
+    },
+    getGlobalScore(team) {
+      var globalScore = 0
+      team.donePuzzles.forEach(puzzle => {
+        if (puzzle.score)
+          globalScore += parseInt(puzzle.coef)*parseInt(puzzle.score)
+        else if (puzzle.validated)
+          globalScore += parseInt(puzzle.coef)
+        
+      });
+      return globalScore;
+    },
+    sortTeams() {
+      this.teams.sort((a, b) => {
+        return this.getGlobalScore(b) - this.getGlobalScore(a)
+      })
     }
   }
+  
 };
 </script>
 
diff --git a/client/src/components/TeamAdder.vue b/client/src/components/TeamAdder.vue
index 22997ee323f71219a7be23c79c4daec0df3ebcff..9c95987aa244bf29fbae39827a1eb1f8cad73e9f 100644
--- a/client/src/components/TeamAdder.vue
+++ b/client/src/components/TeamAdder.vue
@@ -53,7 +53,8 @@ export default {
   },
   methods: {
     addTeam() {
-      let uri = "//localhost:3000/school/addTeam";
+      var domainName = '//'+location.hostname+(location.port ? ':'+location.port: '');
+      let uri = domainName + "/school/addTeam";
       this.axios
         .post(uri, this.team, { withCredentials: true })
         .then(response => {
diff --git a/client/src/components/TeamElement.vue b/client/src/components/TeamElement.vue
index b4c5bce200f67ce712488753a330a466850cb76f..09fca685c82243b32a1eb7aef46f73a34750281c 100644
--- a/client/src/components/TeamElement.vue
+++ b/client/src/components/TeamElement.vue
@@ -85,7 +85,11 @@
               Veuillez scanner une carte sur le lecteur pour l'associer à cette
               équipe. <br>
               <br>
-              ATTENTION : Ceci effacera le contenu actuel de cette carte !
+              ATTENTION : Ceci effacera le contenu actuel de cette carte ! Vous ne pourrez pas attribuer à cette équipe une carte déjà attribuée à une autre équipe.
+              Merci donc de dissocier toutes les cartes de votre équipe une fois le jeu fini.
+              <br>
+              <br>
+              Vous devez avoir connecté le lecteur USB au site. Déposez la carte d'équipe sur le lecteur NFC (face en plastique). Vous devez entendre deux bip consécutifs. Si cette fenêtre se ferme, c'est bon ! Si cela prend du temps ou qu'il n'y a qu'un seul bip, fermez et recommencez. Si le problème persiste, débranchez le lecteur, rechargez la page puis rebranchez le lecteur.
             </div>
           </div>
         </div>
@@ -138,7 +142,8 @@ export default {
 
   methods: {
     removeTeam: function() {
-      let uri = `//localhost:3000/school/deleteTeam/${this.team._id}`;
+      var domainName = '//'+location.hostname+(location.port ? ':'+location.port: '');
+      let uri = domainName + `/school/deleteTeam/${this.team._id}`;
       this.axios.delete(uri, { withCredentials: true }).then(response => {
         console.log("bien supprimé !", response);
         this.teamArray.splice(this.teamArray.indexOf(this.team), 1);
@@ -148,33 +153,40 @@ export default {
     manageCardPairing: function() {
       this.showPairingModal = !this.showPairingModal
       console.log("Trying to reset card")
-      this.$parent.$parent.usbNfcReader.writeCard("team").then(response=> {
-        console.log("Reset successful, trying to read uid", response)
-        this.$parent.$parent.usbNfcReader.readTagUid()
-        .then(response => {   
-          let uri = `//localhost:3000/school/updateTeamCard/${this.team._id}`;
-          this.axios
-          .post(uri, {cardId: response}, { withCredentials: true })
-          .then(() => {
-            console.log("Carte ajoutée !");
-            this.team.cardId = response   
-            this.showPairingModal = false;
-            this.$forceUpdate()
-          }).catch(response => {
-            this.showPairingModal = false;
-            this.showAlreadyPairedError = true;
-            this.team.cardId = "";
-            this.$forceUpdate()
-            console.log("Carte déjà utilisée !", response)
+      this.$parent.$parent.usbNfcReader.cleanCard().then(()=> {
+      this.$parent.$parent.usbNfcReader.formatCard().then(()=> {
+      this.$parent.$parent.usbNfcReader.eraseCard().then(()=> {
+        this.$parent.$parent.usbNfcReader.writeCard("team").then(response=> {
+          console.log("Reset successful, trying to read uid", response)
+          this.$parent.$parent.usbNfcReader.readTagUid()
+          .then(response => {   
+            var domainName = '//'+location.hostname+(location.port ? ':'+location.port: '');
+            let uri = domainName + `/school/updateTeamCard/${this.team._id}`;
+            this.axios
+            .post(uri, {cardId: response}, { withCredentials: true })
+            .then(() => {
+              console.log("Carte ajoutée !");
+              this.team.cardId = response   
+              this.showPairingModal = false;
+              this.$forceUpdate()
+            }).catch(response => {
+              this.showPairingModal = false;
+              this.showAlreadyPairedError = true;
+              this.team.cardId = "";
+              this.$forceUpdate()
+              console.log("Carte déjà utilisée !", response)
+            })
+        
           })
-      
         })
       })
-      
+      })
+      })
     },
 
     removeCardPairing: function() {
-      let uri = `//localhost:3000/school/removeTeamCard/${this.team._id}`;
+      var domainName = '//'+location.hostname+(location.port ? ':'+location.port: '');
+      let uri = domainName `/school/removeTeamCard/${this.team._id}`;
         this.axios
         .post(uri, this.team, { withCredentials: true })
         .then(response => {
diff --git a/client/src/puzzles.json b/client/src/puzzles.json
new file mode 100644
index 0000000000000000000000000000000000000000..d65d9e7a4b680c8370844260f347556ffd8a599e
--- /dev/null
+++ b/client/src/puzzles.json
@@ -0,0 +1,15 @@
+{
+"C": {   
+    "name": "Faire une recette de saison",
+    "room": "Cuisine",
+    "type":"number",
+    "maxScore": 100,
+    "coef":5
+    },
+"A": {  
+    "name": "Manger des pommes",
+    "room": "Cuisine",
+    "type":"boolean",
+    "coef":20
+    }
+}
\ No newline at end of file
diff --git a/client/src/usbNfcReader.js b/client/src/usbNfcReader.js
index 343ce93c2a26b329138be28f9e56e4c70a0c914d..c8a185dfb75ebf6d13b53676d4fd6f711070383c 100644
--- a/client/src/usbNfcReader.js
+++ b/client/src/usbNfcReader.js
@@ -3,6 +3,7 @@ import Serial from "./serial.js"
 export default class UsbNfcReader {
     constructor() {
         this.textEncoder = new TextEncoder();
+        this.locked = false;
         //Tentative de connexion/reconnexion automatique
         Serial.getPorts().then(ports => {
             if (ports.length == 0) {
@@ -53,6 +54,7 @@ export default class UsbNfcReader {
 
     readTagUid() {
       return new Promise((resolve, reject) => {
+        this.locked = true;
         this.sendString("GETID_")
         this.port.onReceive = data => {
           let textDecoder = new TextDecoder();
@@ -63,7 +65,8 @@ export default class UsbNfcReader {
           if (msg == "RECEIVED_GETID;") {
             console.log("GETID request ACK by Arduino")
           } else if (cmdIdentifier == "UID" && msg.slice(-1) == ';') {
-            resolve(msg.split('_')[1].slice(0, -1))
+            this.locked = false;
+            resolve(msg.split('_')[1].slice(0, -1))        
           } else {
             reject("Bad message structure received")
           }
@@ -72,8 +75,35 @@ export default class UsbNfcReader {
       })
     }
 
+    readCard() {
+      return new Promise((resolve, reject) => {
+        this.locked = true;
+        this.sendString("READ_")
+        var failCount = 0
+        var msg = ""
+        this.port.onReceive = data => {
+          let textDecoder = new TextDecoder();
+          let msgBuff = textDecoder.decode(data);
+          msgBuff = msgBuff.replace(/(\r\n|\n|\r)/gm, "").replace(/[^\w;]+/g, '');
+          msg += msgBuff
+          if (msg.includes("CONTENT_BEGIN_en") && msg.includes("_END")) {
+            msg = msg.split("CONTENT_BEGIN_en")
+            msg = msg[msg.length-1].split("_END")[0]
+            this.locked = false;
+            resolve(msg)
+          } else if (!msg.includes("RECEIVED_READ")) {
+            if (failCount > 100) {
+              reject("Too many reading fail")
+            }
+            failCount++
+          }
+        }
+      })
+    }
+
     writeCard(content) {
       return new Promise((resolve, reject) => {
+        this.locked = true;
         this.sendString("WRITE_" + content)
         this.port.onReceive = data => {
           let textDecoder = new TextDecoder();
@@ -82,6 +112,7 @@ export default class UsbNfcReader {
           console.log("recu ", msg)
           if (msg == "WRITTEN;") {
             console.log("wrote team message")
+            this.locked = false;
             resolve("")
           } else if (!msg.includes("RECEIVED_WRITE")) {
             reject("Write : Bad message structure received")
@@ -92,6 +123,7 @@ export default class UsbNfcReader {
 
     cleanCard() {
       return new Promise((resolve, reject) => {
+        this.locked = true;
         this.sendString("CLEAN_")
         this.port.onReceive = data => {
           let textDecoder = new TextDecoder();
@@ -100,16 +132,61 @@ export default class UsbNfcReader {
           console.log("recu ", msg)
           if (msg == "CLEANED;") {
             console.log("Cleaned card")
+            this.locked = false;
             resolve("")
-          } else if (msg != "RECEIVED_CLEAN;") {
+          } else if (!msg.includes("RECEIVED_CLEAN")) {
             reject("Clean : Bad message structure received")
           }
         }
       })
     }
 
+    formatCard() {
+      return new Promise((resolve, reject) => {
+        this.locked = true;
+        this.sendString("FORMAT_")
+        this.port.onReceive = data => {
+          let textDecoder = new TextDecoder();
+          let msg = textDecoder.decode(data);
+          msg = msg.replace(/(\r\n|\n|\r)/gm, "");
+          console.log("recu ", msg)
+          if (msg == "FORMATED;") {
+            console.log("Formated card")
+            this.locked = false;
+            resolve("")
+          } else if (!msg.includes("RECEIVED_FORMAT")) {
+            reject("Format : Bad message structure received")
+          }
+        }
+      })
+    }
+
+    eraseCard() {
+      return new Promise((resolve, reject) => {
+        this.locked = true;
+        this.sendString("ERASE_")
+        this.port.onReceive = data => {
+          let textDecoder = new TextDecoder();
+          let msg = textDecoder.decode(data);
+          msg = msg.replace(/(\r\n|\n|\r)/gm, "");
+          console.log("recu ", msg)
+          if (msg == "ERASED;") {
+            console.log("Erased card")
+            this.locked = false;
+            resolve("")
+          } else if (!msg.includes("RECEIVED_ERASE")) {
+            reject("Erase : Bad message structure received")
+          }
+        }
+      })
+    }
+
     ping() {
       return new Promise((resolve, reject) => {
+        if (this.locked) {
+          console.log("Trying to ping while performing another task")
+          return resolve("")
+        }
         this.sendString("PING_")
         var timeout = setTimeout(() => {
           reject("ping timeout")}
diff --git a/server/db/puzzle.model.js b/server/db/puzzle.model.js
index 27b9a1297611c8887ed8de9aa5cf9a4ab2abd348..6cbbc4b7706a6ffb9a139d6102de9d7741d064b6 100644
--- a/server/db/puzzle.model.js
+++ b/server/db/puzzle.model.js
@@ -6,7 +6,8 @@ var Puzzle = Schema({
     room: String,
     validated: Boolean,
     score: Number,
-    maxScore: Number
+    maxScore: Number,
+    coef: Number
 })
 
 module.exports = mongoose.model('Puzzle', Puzzle)
\ No newline at end of file
diff --git a/server/db/team.route.js b/server/db/team.route.js
index 060ec5141324afb67b8d0b1b71baa14cc7ad0027..9f71e252337ad6ef4b3304e286974759a850053a 100644
--- a/server/db/team.route.js
+++ b/server/db/team.route.js
@@ -66,6 +66,14 @@ router.route('/updateTeamCard/:id').post(function (req, res) {
   }
 });
 
+router.route('/getTeamByCardID/:cardId').get(function (req, res) {
+    console.log("GETing team for :", req.params.cardId)
+    Team.find({cardId: req.params.cardId}, function (err, team) {
+      if (err) {res.json(err)}
+      else {res.json(team)}
+    });
+});
+
 router.route('/removeTeamCard/:id').post(function (req, res) {
   if (req.user) {
     console.log("Request for removing card ID")