diff --git a/nodemon.json b/nodemon.json
index a6c46bd997c2a437d6944ca8d25f8a17bbc548e1..e33fc45722c7966c12bd1c91320e004d3eb10b2b 100644
--- a/nodemon.json
+++ b/nodemon.json
@@ -7,9 +7,9 @@
   },
 
   "runOnChangeOnly": false,
-  "watch": ["src/**/*.js"],
+  "watch": ["src/**/*"],
   "env": {
     "NODE_ENV": "development"
   },
-  "ext": "js,json"
+  "ext": "js,json,yml"
 }
diff --git a/package-lock.json b/package-lock.json
index f887e7809c5c636707a6f8465b69168c9b0285ef..1d4e4ef59f82b52c27cb19b5a36cdaec1035a086 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4,6 +4,40 @@
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
+    "@apidevtools/json-schema-ref-parser": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-8.0.0.tgz",
+      "integrity": "sha512-n4YBtwQhdpLto1BaUCyAeflizmIbaloGShsPyRtFf5qdFJxfssj+GgLavczgKJFa3Bq+3St2CKcpRJdjtB4EBw==",
+      "requires": {
+        "@jsdevtools/ono": "^7.1.0",
+        "call-me-maybe": "^1.0.1",
+        "js-yaml": "^3.13.1"
+      }
+    },
+    "@apidevtools/openapi-schemas": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.0.4.tgz",
+      "integrity": "sha512-ob5c4UiaMYkb24pNhvfSABShAwpREvUGCkqjiz/BX9gKZ32y/S22M+ALIHftTAuv9KsFVSpVdIDzi9ZzFh5TCA=="
+    },
+    "@apidevtools/swagger-methods": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz",
+      "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg=="
+    },
+    "@apidevtools/swagger-parser": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-9.0.1.tgz",
+      "integrity": "sha512-Irqybg4dQrcHhZcxJc/UM4vO7Ksoj1Id5e+K94XUOzllqX1n47HEA50EKiXTCQbykxuJ4cYGIivjx/MRSTC5OA==",
+      "requires": {
+        "@apidevtools/json-schema-ref-parser": "^8.0.0",
+        "@apidevtools/openapi-schemas": "^2.0.2",
+        "@apidevtools/swagger-methods": "^3.0.0",
+        "@jsdevtools/ono": "^7.1.0",
+        "call-me-maybe": "^1.0.1",
+        "openapi-types": "^1.3.5",
+        "z-schema": "^4.2.2"
+      }
+    },
     "@babel/code-frame": {
       "version": "7.10.4",
       "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
@@ -627,6 +661,11 @@
         "chalk": "^4.0.0"
       }
     },
+    "@jsdevtools/ono": {
+      "version": "7.1.3",
+      "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
+      "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg=="
+    },
     "@sindresorhus/is": {
       "version": "0.14.0",
       "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
@@ -1043,7 +1082,6 @@
       "version": "1.0.10",
       "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
       "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
-      "dev": true,
       "requires": {
         "sprintf-js": "~1.0.2"
       }
@@ -1209,8 +1247,7 @@
     "balanced-match": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
-      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
-      "dev": true
+      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
     },
     "base": {
       "version": "0.11.2",
@@ -1427,7 +1464,6 @@
       "version": "1.1.11",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
       "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
-      "dev": true,
       "requires": {
         "balanced-match": "^1.0.0",
         "concat-map": "0.0.1"
@@ -1522,6 +1558,11 @@
         }
       }
     },
+    "call-me-maybe": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz",
+      "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms="
+    },
     "callsites": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
@@ -1755,6 +1796,11 @@
         "delayed-stream": "~1.0.0"
       }
     },
+    "commander": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-5.0.0.tgz",
+      "integrity": "sha512-JrDGPAKjMGSP1G0DUoaceEJ3DZgAfr/q6X7FVk4+U5KxUSKviYGM2k6zWkfyyBHy5rAtzgYJFa1ro2O9PtoxwQ=="
+    },
     "commondir": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
@@ -1770,8 +1816,7 @@
     "concat-map": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
-      "dev": true
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
     },
     "configstore": {
       "version": "5.0.1",
@@ -2091,7 +2136,6 @@
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
       "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
-      "dev": true,
       "requires": {
         "esutils": "^2.0.2"
       }
@@ -2513,8 +2557,7 @@
     "esprima": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
-      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
-      "dev": true
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
     },
     "esquery": {
       "version": "1.3.1",
@@ -2551,8 +2594,7 @@
     "esutils": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
-      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
-      "dev": true
+      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
     },
     "etag": {
       "version": "1.8.1",
@@ -3036,8 +3078,7 @@
     "fs.realpath": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
-      "dev": true
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
     },
     "fsevents": {
       "version": "2.1.3",
@@ -3104,7 +3145,6 @@
       "version": "7.1.6",
       "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
       "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
-      "dev": true,
       "requires": {
         "fs.realpath": "^1.0.0",
         "inflight": "^1.0.4",
@@ -3373,7 +3413,6 @@
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
       "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
-      "dev": true,
       "requires": {
         "once": "^1.3.0",
         "wrappy": "1"
@@ -4269,7 +4308,6 @@
       "version": "3.14.0",
       "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
       "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==",
-      "dev": true,
       "requires": {
         "argparse": "^1.0.7",
         "esprima": "^4.0.0"
@@ -4477,6 +4515,16 @@
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
       "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
     },
+    "lodash.get": {
+      "version": "4.4.2",
+      "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
+      "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
+    },
+    "lodash.isequal": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+      "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
+    },
     "lodash.sortby": {
       "version": "4.7.0",
       "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
@@ -4601,7 +4649,6 @@
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
       "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
-      "dev": true,
       "requires": {
         "brace-expansion": "^1.1.7"
       }
@@ -4998,7 +5045,6 @@
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
       "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
-      "dev": true,
       "requires": {
         "wrappy": "1"
       }
@@ -5012,6 +5058,11 @@
         "mimic-fn": "^2.1.0"
       }
     },
+    "openapi-types": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-1.3.5.tgz",
+      "integrity": "sha512-11oi4zYorsgvg5yBarZplAqbpev5HkuVNPlZaPTknPDzAynq+lnJdXAmruGWP0s+dNYZS7bjM+xrTpJw7184Fg=="
+    },
     "optionator": {
       "version": "0.9.1",
       "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
@@ -5173,8 +5224,7 @@
     "path-is-absolute": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
-      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
-      "dev": true
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
     },
     "path-key": {
       "version": "3.1.1",
@@ -6248,8 +6298,7 @@
     "sprintf-js": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
-      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
-      "dev": true
+      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
     },
     "sshpk": {
       "version": "1.16.1",
@@ -6486,6 +6535,50 @@
         }
       }
     },
+    "swagger-jsdoc": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/swagger-jsdoc/-/swagger-jsdoc-4.0.0.tgz",
+      "integrity": "sha512-wHrmRvE/OQa3d387YIrRNPvsPwxkJc0tAYeCVa359gUIKPjC4ReduFhqq/+4erLUS79kY1T5Fv0hE0SV/PgBig==",
+      "requires": {
+        "commander": "5.0.0",
+        "doctrine": "3.0.0",
+        "glob": "7.1.6",
+        "js-yaml": "3.13.1",
+        "swagger-parser": "9.0.1"
+      },
+      "dependencies": {
+        "js-yaml": {
+          "version": "3.13.1",
+          "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
+          "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
+          "requires": {
+            "argparse": "^1.0.7",
+            "esprima": "^4.0.0"
+          }
+        }
+      }
+    },
+    "swagger-parser": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-9.0.1.tgz",
+      "integrity": "sha512-oxOHUaeNetO9ChhTJm2fD+48DbGbLD09ZEOwPOWEqcW8J6zmjWxutXtSuOiXsoRgDWvORYlImbwM21Pn+EiuvQ==",
+      "requires": {
+        "@apidevtools/swagger-parser": "9.0.1"
+      }
+    },
+    "swagger-ui-dist": {
+      "version": "3.30.2",
+      "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.30.2.tgz",
+      "integrity": "sha512-hAu/ig5N8i0trXXbrC7rwbXV4DhpEAsZhYXDs1305OjmDgjGC0thINbb0197idy3Pp+B6w7u426SUM43GAP7qw=="
+    },
+    "swagger-ui-express": {
+      "version": "4.1.4",
+      "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.1.4.tgz",
+      "integrity": "sha512-Ea96ecpC+Iq9GUqkeD/LFR32xSs8gYqmTW1gXCuKg81c26WV6ZC2FsBSPVExQP6WkyUuz5HEiR0sEv/HCC343g==",
+      "requires": {
+        "swagger-ui-dist": "^3.18.1"
+      }
+    },
     "symbol-tree": {
       "version": "3.2.4",
       "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
@@ -7158,8 +7251,7 @@
     "wrappy": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
-      "dev": true
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
     },
     "write": {
       "version": "1.0.3",
@@ -7288,6 +7380,30 @@
           "dev": true
         }
       }
+    },
+    "z-schema": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-4.2.3.tgz",
+      "integrity": "sha512-zkvK/9TC6p38IwcrbnT3ul9in1UX4cm1y/VZSs4GHKIiDCrlafc+YQBgQBUdDXLAoZHf2qvQ7gJJOo6yT1LH6A==",
+      "requires": {
+        "commander": "^2.7.1",
+        "lodash.get": "^4.4.2",
+        "lodash.isequal": "^4.5.0",
+        "validator": "^12.0.0"
+      },
+      "dependencies": {
+        "commander": {
+          "version": "2.20.3",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+          "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+          "optional": true
+        },
+        "validator": {
+          "version": "12.2.0",
+          "resolved": "https://registry.npmjs.org/validator/-/validator-12.2.0.tgz",
+          "integrity": "sha512-jJfE/DW6tIK1Ek8nCfNFqt8Wb3nzMoAbocBF6/Icgg1ZFSBpObdnwVY2jQj6qUqzhx5jc71fpvBWyLGO7Xl+nQ=="
+        }
+      }
     }
   }
 }
diff --git a/package.json b/package.json
index f39a4c319147f40367f8291ba478b2e3a2f8d5b1..90025e9b38a15023166ea015bed7dd66370ec595 100644
--- a/package.json
+++ b/package.json
@@ -28,6 +28,8 @@
     "morgan": "^1.10.0",
     "passport": "^0.4.1",
     "passport-oauth2": "^1.5.0",
+    "swagger-jsdoc": "^4.0.0",
+    "swagger-ui-express": "^4.1.4",
     "validator": "^13.1.1"
   },
   "devDependencies": {
diff --git a/src/resources/activity/activityControllers.js b/src/resources/activity/activityControllers.js
index cec720f870970e1a660b1ca228154cb9139c277b..76c2898781cb1f105564bcb74bc4ba4c8162c60e 100644
--- a/src/resources/activity/activityControllers.js
+++ b/src/resources/activity/activityControllers.js
@@ -1,10 +1,208 @@
-const { crudControllers } = require('../../utils/crud')
 const { Activity } = require('./activityModel')
+const { User } = require('../user/userModel')
+const { Attendance } = require('../attendance/attendanceModel')
+const { Comment } = require('../comment/commentModel')
+const { omit, pick } = require('lodash')
 
-exports.default = crudControllers(Activity, [
+// Config
+const pickedKeys = [
   '_id',
   'title',
   'description',
   'date',
   'type',
-])
+  'createdAt',
+  'updatedAt',
+  'attendance',
+  'comments',
+]
+
+// Controller
+
+module.exports.createOne = async function createOne(req, res) {
+  try {
+    // Invalid Date provided
+    if (!req.body.date || Date.parse(req.body.date) < new Date().getTime())
+      return res.status(403).json({ messages: ['Invalid date'] })
+
+    let activity = await Activity.create({ ...req.body })
+
+    // Create Initial participants
+    if (
+      !(
+        req.body.initialParticipants != null &&
+        req.body.initialParticipants == false
+      )
+    ) {
+      let acceptedUsers = await User.find({ role: 'accepted' }).lean().exec()
+      acceptedUsers = acceptedUsers.map(function getUserSchaccs(user) {
+        return { schacc: user.schacc }
+      })
+
+      let attendances = activity.attendance
+      for await (let user of acceptedUsers) {
+        const newAttendance = await Attendance.create({
+          activity: activity._id,
+          user: user.schacc,
+        })
+        attendances.push(newAttendance._id)
+      }
+
+      await Activity.findOneAndUpdate(
+        { _id: activity._id },
+        { attendance: attendances },
+        { new: true }
+      )
+        .lean()
+        .exec()
+    }
+
+    return res
+      .status(200)
+      .json({
+        data: pick(activity, pickedKeys),
+      })
+      .end()
+  } catch (err) {
+    if (err.name == 'ValidationError') {
+      // Throwed by Mongoose
+      let messages = []
+      for (field in err.errors) {
+        messages.push(err.errors[field].message)
+      }
+      return res.status(422).json({ messages })
+    }
+    console.error(err)
+    return res.status(500).json({ message: err.message })
+  }
+}
+
+module.exports.getOne = async function getOne(req, res) {
+  try {
+    const activity = await Activity.findOne({ _id: req.params.id })
+      .lean()
+      .exec()
+
+    if (!activity)
+      return res.status(404).json({ messages: ['No such activity.'] })
+
+    if (req.user.role == 'mentor')
+      return res.status(200).json({
+        data: pick(activity, pickedKeys),
+      })
+    return res.status(200).json({
+      data: pick(activity, [
+        '_id',
+        'title',
+        'description',
+        'date',
+        'type',
+        'createdAt',
+        'updatedAt',
+      ]),
+    })
+  } catch (err) {
+    if (err.name == 'ValidationError') {
+      // Throwed by Mongoose
+      let messages = []
+      for (field in err.errors) {
+        messages.push(err.errors[field].message)
+      }
+      return res.status(422).json({ messages })
+    }
+    console.error(err)
+    return res.status(500).json({ message: err.message })
+  }
+}
+
+module.exports.getMany = async function getMany(req, res) {
+  try {
+    const activity = await Activity.find().select('-__v').lean().exec()
+
+    if (!activity)
+      return res.status(404).json({ message: 'Activity not found!' })
+
+    res.status(200).json({
+      data: activity.map(function pickKeys(doc) {
+        return pick(populatedActivity, pickedKeys)
+      }),
+    })
+  } catch (err) {
+    if (err.name == 'ValidationError') {
+      // Throwed by Mongoose
+      let messages = []
+      for (field in err.errors) {
+        messages.push(err.errors[field].message)
+      }
+      return res.status(422).json({ messages })
+    }
+    console.error(err)
+    res.status(500).json({ message: err.message })
+  }
+}
+
+module.exports.removeOne = async function removeOne(req, res) {
+  try {
+    const activity = await Activity.findByIdAndDelete({
+      _id: req.params.id,
+    })
+      .lean()
+      .exec()
+
+    if (!activity)
+      return res.status(404).json({ message: 'Activity not found!' })
+
+    await Attendance.deleteMany({
+      _id: activity.attendance.map(function getAttendanceIds(element) {
+        return element._id
+      }),
+    })
+
+    await Comment.deleteMany({
+      _id: activity.comments.map(function getCommentIds(element) {
+        return element._id
+      }),
+    })
+
+    return res.status(200).json({ data: pick(activity, pickedKeys) })
+  } catch (err) {
+    if (err.name == 'ValidationError') {
+      // Throwed by Mongoose
+      let messages = []
+      for (field in err.errors) {
+        messages.push(err.errors[field].message)
+      }
+      return res.status(422).json({ messages })
+    }
+    console.error(err)
+    return res.status(500).json({ message: err.message })
+  }
+}
+
+module.exports.updateOne = async function updateOne(req, res) {
+  try {
+    const activity = await Activity.findOneAndUpdate(
+      { _id: req.params.id },
+      omit(req.body, ['attendance', 'comments']),
+      { new: true }
+    )
+      .lean()
+      .exec()
+
+    if (!activity)
+      return res.status(404).json({ message: 'Activity not found!' })
+
+    res.status(200).json({ data: pick(activity, pickedKeys) })
+  } catch (err) {
+    if (err.name == 'ValidationError') {
+      // Throwed by Mongoose
+      let messages = []
+      for (field in err.errors) {
+        messages.push(err.errors[field].message)
+      }
+      return res.status(422).json({ messages })
+    }
+    console.error(err)
+    res.status(500).json({ message: err.message })
+  }
+}
diff --git a/src/resources/activity/activityDocs.yml b/src/resources/activity/activityDocs.yml
new file mode 100644
index 0000000000000000000000000000000000000000..d16d409a2ff3ff47b022edc04ea1bb623d648475
--- /dev/null
+++ b/src/resources/activity/activityDocs.yml
@@ -0,0 +1,119 @@
+openapi: '3.0.2'
+info:
+  title: 'Activity Endpoint'
+  version: '1.0'
+
+paths:
+  /activity:
+    get:
+      tags:
+        - 'Activity'
+      summary: 'Get a List of comments'
+      description: 'Have to be logged in for this.'
+      operationId: 'getAllActivity'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: 'array'
+                items:
+                  $ref: '#/components/schemas/Activity'
+    post:
+      tags:
+        - 'Activity'
+      summary: 'Create a activity'
+      description: 'Only mentors can create activity.'
+      operationId: 'createActivity'
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Activity'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Activity'
+  /activity/{id}:
+    get:
+      tags:
+        - 'Activity'
+      summary: 'Get a activity by ID'
+      description: 'Have to be logged in for this.'
+      operationId: 'getActivity'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Activity'
+    put:
+      tags:
+        - 'Activity'
+      summary: 'Update an activity by ID'
+      description: 'Only mentors can update an activity.'
+      operationId: 'updateOneActivity'
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Activity'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Activity'
+    delete:
+      tags:
+        - 'Activity'
+      summary: 'Delete an activity by ID'
+      description: 'Only mentors can delete an activity.'
+      operationId: 'deleteActivity'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Activity'
+
+components:
+  schemas:
+    Activity:
+      type: object
+      properties:
+        title:
+          type: string
+        description:
+          type: string
+        date:
+          type: string
+          format: date-time
+        type:
+          type: string
+          enum:
+            - class
+            - optional
+            - camp
+        attendance:
+          type: array
+          items:
+            type: string
+            description: cuid of each attendance
+        comments:
+          type: array
+          items:
+            type: string
+            description: cuid of each comment
+      required:
+        - title
+        - description
+        - date
+        - type
diff --git a/src/resources/activity/activityModel.js b/src/resources/activity/activityModel.js
index fa90dd75f31c2d2f1892b761ae7d019ecbb805e9..bbf2a8750a205d1720cb235c00d035cfed9f2804 100644
--- a/src/resources/activity/activityModel.js
+++ b/src/resources/activity/activityModel.js
@@ -25,20 +25,16 @@ const ActivitySchema = new mongoose.Schema(
         ref: 'attendance',
       },
     ],
-    comment: [
+    comments: [
       {
         type: mongoose.Schema.Types.ObjectId,
         ref: 'comment',
-        required: true,
       },
     ],
   },
   { timestamps: true }
 )
 
-// Careful with the docs, there are some deprecated ones
-// https://mongoosejs.com/docs/guide.html
-
 const Activity = mongoose.model('activity', ActivitySchema)
 
 exports.Activity = Activity
diff --git a/src/resources/activity/activityRouter.js b/src/resources/activity/activityRouter.js
index 6136da10fd53bf472ca8404afca75d9029e022b4..e8c18a460d100c1a41d50478d56ee3473a6046bd 100644
--- a/src/resources/activity/activityRouter.js
+++ b/src/resources/activity/activityRouter.js
@@ -1,19 +1,20 @@
 const { Router } = require('express')
 const controllers = require('./activityControllers')
+const { isLoggedIn, isMentor } = require('../../middlewares/auth')
 
 const router = Router()
 
-// /api/item
+// /api/v1/activity
 router
   .route('/')
-  .get(controllers.default.getMany)
-  .post(controllers.default.createOne)
+  .get(isLoggedIn, controllers.getMany)
+  .post(isLoggedIn, isMentor, controllers.createOne)
 
-// /api/item/:id
+// /api/v1/activity/:id
 router
   .route('/:id')
-  .get(controllers.default.getOne)
-  .put(controllers.default.updateOne)
-  .delete(controllers.default.removeOne)
+  .get(isLoggedIn, controllers.getOne)
+  .put(isLoggedIn, isMentor, controllers.updateOne)
+  .delete(isLoggedIn, isMentor, controllers.removeOne)
 
 exports.default = router
diff --git a/src/resources/application/__tests__/applicationFuncTest.js b/src/resources/application/__tests__/applicationFuncTest.js
index 35e5918eaaeeaec24d37c5e588e8bce1628720ec..a2b397947a51dbbeaa2d5041645be7fccbb5d62a 100644
--- a/src/resources/application/__tests__/applicationFuncTest.js
+++ b/src/resources/application/__tests__/applicationFuncTest.js
@@ -66,32 +66,36 @@ describe('/application "Mentor" Functionality', () => {
     })
   })
   // GET own
-  test(`GET own application`, async () => {
+  test(`GET own application by ID`, async () => {
     await createGroups()
-    const ownUser = await authSession.get('/api/v1/extra/me')
+    const ownUser = await authSession.get('/api/v1/user/me')
     const newApplication = await Application.create(
       Object.assign({}, fakeApplicationJson, {
         creator: ownUser.body.data.schacc,
       })
     )
-    let response = await authSession.get(`${endpointUrl}/${newApplication._id}`)
+    let response = await authSession.get(
+      `${endpointUrl}/id/${newApplication._id}`
+    )
 
     expect(response.statusCode).toBe(200)
     validateKeys(response.body.data, defaultKeys)
-    response = await authSession.get(`${endpointUrl}/own`)
+    response = await authSession.get(`${endpointUrl}/id/own`)
     expect(response.statusCode).toBe(200)
     validateKeys(response.body.data, defaultKeys)
   })
   // Get others
-  test(`GET others application`, async () => {
+  test(`GET others application by ID`, async () => {
     await createGroups()
     const newApplication = await Application.create(fakeApplicationJson)
-    let response = await authSession.get(`${endpointUrl}/${newApplication._id}`)
+    let response = await authSession.get(
+      `${endpointUrl}/id/${newApplication._id}`
+    )
 
     expect(response.statusCode).toBe(200)
   })
   test(`GET invalid ID`, async () => {
-    let response = await authSession.get(`${endpointUrl}/almafa`)
+    let response = await authSession.get(`${endpointUrl}/id/almafa`)
 
     expect(response.statusCode).toBe(422)
   })
diff --git a/src/resources/application/__tests__/applicationPermTest.js b/src/resources/application/__tests__/applicationPermTest.js
index f00f695410daab998add6a882e15464f47593437..a5f94fd5d707835370e25ccacfbfe8689e1922d3 100644
--- a/src/resources/application/__tests__/applicationPermTest.js
+++ b/src/resources/application/__tests__/applicationPermTest.js
@@ -1,7 +1,10 @@
 const { app } = require('../../../server')
+const session = require('supertest-session')
 const { crudPermTest } = require('../../../utils/testHelpers')
 
 const { Application } = require('../applicationModel')
+const { User } = require('../../user/userModel')
+const { Groups } = require('../../groups/groupsModel')
 
 const endpointUrl = '/api/v1/application'
 
@@ -9,17 +12,38 @@ let fakeApplicationJson = {
   motivation: 'what is motivation?',
   expectation: 'I expect a lot',
   solution: 'My awesome solution',
-  groups: ['5f089da3d11dae2a1ff07abc'],
+  groups: ['5f089da3d11dae2a1ff0aaaa', '5f089da3d11dae2a1f00aaab'],
+}
+
+const fakeGroupsJsons = [
+  {
+    _id: '5f089da3d11dae2a1ff0aaaa',
+    name: 'SuperGroup',
+    description: 'So awesome that you want to join in',
+    groupPath: 'future image',
+  },
+  {
+    _id: '5f089da3d11dae2a1f00aaab',
+    name: 'AwesomeGroup',
+    description: 'So awesome that you want to join in',
+    groupPath: 'future image',
+  },
+]
+
+const createGroups = async () => {
+  await Groups.create(fakeGroupsJsons[0])
+  await Groups.create(fakeGroupsJsons[1])
 }
 
 describe('/application Permission tests', () => {
+  let authSession
   crudPermTest(
     app,
     endpointUrl,
     Application,
     'application',
     fakeApplicationJson,
-    [true, true, true, false, false],
+    [true, true, false, false, false],
     [
       // [role, create, readAll, readOne, update, delete]
       ['none', false, false, false, false, false],
@@ -28,4 +52,73 @@ describe('/application Permission tests', () => {
       ['mentor', true, true, true, false, false],
     ]
   )
+  crudPermTest(
+    app,
+    endpointUrl + '/id',
+    Application,
+    'application',
+    fakeApplicationJson,
+    [false, false, true, false, false],
+    [
+      // [role, create, readAll, readOne, update, delete]
+      ['none', false, false, false, false, false],
+      ['normal', true, false, false, false, false],
+      ['accepted', true, false, false, false, false],
+      ['mentor', true, true, true, false, false],
+    ]
+  )
+  describe.each(['normal', 'accepted', 'mentor'])('role: %s', (role) => {
+    beforeEach(function (done) {
+      let testSession = session(app)
+      testSession.get(`/api/v1/login/mock/${role}`).end(function (err) {
+        if (err) return done(err)
+        authSession = testSession
+        return done()
+      })
+    })
+    // All roles
+    test(`Can Get own application on /id/ or on /schacc`, async () => {
+      await createGroups()
+      const ownUser = await authSession.get('/api/v1/user/me')
+      const newApplication = await Application.create(
+        Object.assign({}, fakeApplicationJson, {
+          creator: ownUser.body.data.schacc,
+        })
+      )
+      let response = await authSession.get(
+        `${endpointUrl}/id/${newApplication._id}`
+      )
+      expect(response.statusCode).toBe(200)
+      response = await authSession.get(
+        `${endpointUrl}/schacc/${ownUser.body.data.schacc}`
+      )
+      expect(response.statusCode).toBe(200)
+
+      // get others
+      const newUser = await User.create({
+        internal_id: 'fakeId',
+        schacc: 'fakeUser',
+        fullName: 'faker Janos',
+        secondaryEmail: 'faker@fake.com',
+      })
+      const newApplication2 = await Application.create(
+        Object.assign({}, fakeApplicationJson, {
+          creator: newUser.schacc,
+        })
+      )
+      let responsebyId = await authSession.get(
+        `${endpointUrl}/id/${newApplication2._id}`
+      )
+      let responsebySchacc = await authSession.get(
+        `${endpointUrl}/schacc/${newUser.schacc}`
+      )
+      if (role == 'mentor') {
+        expect(responsebyId.statusCode).toBe(200)
+        expect(responsebySchacc.statusCode).toBe(200)
+      } else {
+        expect(responsebyId.statusCode).toBe(403)
+        expect(responsebySchacc.statusCode).toBe(403)
+      }
+    })
+  })
 })
diff --git a/src/resources/application/applicationControllers.js b/src/resources/application/applicationControllers.js
index a449c8daca9d0140b8adc0bc196ee48e9a00c907..22be0bbbf6322f0eb5e7e734ed2b478faa4b121a 100644
--- a/src/resources/application/applicationControllers.js
+++ b/src/resources/application/applicationControllers.js
@@ -162,7 +162,7 @@ exports.default.getMany = async (req, res) => {
   }
 }
 
-exports.default.getOne = async (req, res) => {
+exports.default.getOneByID = async (req, res) => {
   try {
     let doc
     if (req.params.id === 'own')
@@ -179,6 +179,47 @@ exports.default.getOne = async (req, res) => {
       return res.status(404).end()
     }
 
+    if (doc.creator != req.user.schacc && req.user.role != 'mentor')
+      return res.status(403).end()
+
+    doc.creator = doc._creator
+    res.status(200).json({
+      data: pick(doc, [
+        '_id',
+        'creator',
+        'motivation',
+        'expectation',
+        'solution',
+        'groups',
+        'state',
+      ]),
+    })
+  } catch (err) {
+    if (err.name == 'CastError') {
+      // Throwed by Mongoose
+      return res.status(422).json('Invalid ID provided')
+    } else {
+      console.error(err)
+      res.status(400).end()
+    }
+  }
+}
+
+exports.default.getOneBySchacc = async (req, res) => {
+  try {
+    let doc = await Application.findOne({ creator: req.params.schacc })
+      .populate('groups', ['name'])
+      .populate('_creator', ['schacc', 'fullName', 'secondaryEmail'])
+      .lean()
+      .exec()
+
+    if (!doc) {
+      return res.status(404).end()
+    }
+
+    if (doc.creator != req.user.schacc && req.user.role != 'mentor')
+      return res.status(403).end()
+
     doc.creator = doc._creator
     res.status(200).json({
       data: pick(doc, [
diff --git a/src/resources/application/applicationDocs.yml b/src/resources/application/applicationDocs.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1bab936fd6b6a75f651852d30e1da989012a0cfc
--- /dev/null
+++ b/src/resources/application/applicationDocs.yml
@@ -0,0 +1,110 @@
+openapi: '3.0.2'
+info:
+  title: 'Application Endpoint'
+  version: '1.0'
+
+paths:
+  /application:
+    get:
+      tags:
+        - 'Application'
+      summary: 'Get a List of applications'
+      description: 'This can only be done by a mentor.'
+      operationId: 'getAllApplication'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: 'array'
+                items:
+                  $ref: '#/components/schemas/Application'
+    post:
+      tags:
+        - 'Application'
+      summary: 'Update an application or create it if doesnt exist'
+      description: 'Have to be logged in.
+        To update someones application as a mentor, have to pass in the creator.
+        After deadline only the mentor can create or update one.
+        Group names have to be passed instead of ids.'
+      operationId: 'createAnApplication'
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Application'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Application'
+  /application/id/{id}:
+    get:
+      tags:
+        - 'Application'
+      summary: 'Get Application by ID'
+      description: 'Can get own or have to be mentor.
+        {id} = own is a shorthand for getting own.'
+      operationId: 'getApplicationByID'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: 'array'
+                items:
+                  $ref: '#/components/schemas/Application'
+  /application/schacc/{schacc}:
+    get:
+      tags:
+        - 'Application'
+      summary: 'Get Application by Schacc'
+      description: 'Can get own or have to be mentor.'
+      operationId: 'getApplicationBySchacc'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: 'array'
+                items:
+                  $ref: '#/components/schemas/Application'
+
+components:
+  schemas:
+    Application:
+      type: object
+      properties:
+        creator:
+          type: string
+          description: Reference to a Users schacc
+        motivation:
+          type: string
+        expectation:
+          type: string
+          maxLength: 50
+        solution:
+          type: string
+        groups:
+          type: array
+          items:
+            type: string
+            description: References to Group Ids
+        state:
+          type: string
+          enum:
+            - 'accepted'
+            - 'rejected'
+            - 'nonchecked'
+          default: 'nonchecked'
+      required:
+        - creator
+        - motivation
+        - expectation
+        - solution
+        - state
diff --git a/src/resources/application/applicationRouter.js b/src/resources/application/applicationRouter.js
index aba1e12ef6995872b5536af80f2a5fcd44eda2f5..093fbbf514638c179473b9aa58c1c57702c3ab94 100644
--- a/src/resources/application/applicationRouter.js
+++ b/src/resources/application/applicationRouter.js
@@ -4,13 +4,18 @@ const { isLoggedIn, isMentor } = require('../../middlewares/auth')
 
 const router = Router()
 
-// /api/application
+// /api/v1/application
 router
   .route('/')
   .get(isLoggedIn, isMentor, controllers.default.getMany)
   .post(isLoggedIn, controllers.default.createOne)
 
-// /api/application/:id
-router.route('/:id').get(isLoggedIn, controllers.default.getOne)
+// /api/v1/application/id/:id
+router.route('/id/:id').get(isLoggedIn, controllers.default.getOneByID)
+
+// /api/v1/application/schacc/:schacc
+router
+  .route('/schacc/:schacc')
+  .get(isLoggedIn, controllers.default.getOneBySchacc)
 
 exports.default = router
diff --git a/src/resources/attendance/__tests__/attendanceFuncTest.js b/src/resources/attendance/__tests__/attendanceFuncTest.js
index c9836e0e65418149d3f83e1ea96dc9947fd97538..d0858f91e9954b362441ab15c7a38e4eed2f25fd 100644
--- a/src/resources/attendance/__tests__/attendanceFuncTest.js
+++ b/src/resources/attendance/__tests__/attendanceFuncTest.js
@@ -42,7 +42,9 @@ describe('/group "Mentor" Functionality', () => {
   // GET One
   test(`GET returns with allowed keys`, async () => {
     const newAttendance = await Attendance.create(fakeAttendanceJson)
-    let response = await authSession.get(`${endpointUrl}/${newAttendance._id}`)
+    let response = await authSession.get(
+      `${endpointUrl}/id/${newAttendance._id}`
+    )
     expect(response.statusCode).toBe(200)
     validateKeys(response.body.data, defaultKeys)
   })
@@ -58,7 +60,7 @@ describe('/group "Mentor" Functionality', () => {
   })
   // Create
   test(`Create group returns with allowed keys`, async () => {
-    const ownUser = await authSession.get('/api/v1/extra/me')
+    const ownUser = await authSession.get('/api/v1/user/me')
     const newActivity = await Activity.create(fakeActivityJson)
     let response = await authSession.post(endpointUrl).send({
       activity: newActivity._id,
@@ -71,7 +73,7 @@ describe('/group "Mentor" Functionality', () => {
   test(`Delete group returns with allowed keys`, async () => {
     const newAttendance = await Attendance.create(fakeAttendanceJson)
     let response = await authSession.delete(
-      `${endpointUrl}/${newAttendance._id}`
+      `${endpointUrl}/id/${newAttendance._id}`
     )
     expect(response.statusCode).toBe(200)
     validateKeys(response.body.data, defaultKeys)
@@ -80,7 +82,7 @@ describe('/group "Mentor" Functionality', () => {
   test(`Update group returns with allowed keys`, async () => {
     const newAttendance = await Attendance.create(fakeAttendanceJson)
     let response = await authSession
-      .put(`${endpointUrl}/${newAttendance._id}`)
+      .put(`${endpointUrl}/id/${newAttendance._id}`)
       .send({
         state: 'present',
       })
diff --git a/src/resources/attendance/__tests__/attendancePermTest.js b/src/resources/attendance/__tests__/attendancePermTest.js
index 4366a8dced12ccf3ab617e90e63bc3b3d7aa0453..9b9b81c222f35c0fc7a82021de22eb2498dce1cf 100644
--- a/src/resources/attendance/__tests__/attendancePermTest.js
+++ b/src/resources/attendance/__tests__/attendancePermTest.js
@@ -11,13 +11,28 @@ const fakeAttendanceJson = {
 }
 
 describe('/attendance Permission tests', () => {
+  crudPermTest(
+    app,
+    endpointUrl + '/id',
+    Attendance,
+    'attendance',
+    fakeAttendanceJson,
+    [false, false, true, true, true],
+    [
+      // [role, create, readAll, readOne, update, delete]
+      ['none', false, false, false, false, false],
+      ['normal', false, false, false, false, false],
+      ['accepted', false, false, false, false, false],
+      ['mentor', true, true, true, true, true],
+    ]
+  )
   crudPermTest(
     app,
     endpointUrl,
     Attendance,
     'attendance',
     fakeAttendanceJson,
-    [true, true, true, true, true],
+    [true, true, false, false, false],
     [
       // [role, create, readAll, readOne, update, delete]
       ['none', false, false, false, false, false],
diff --git a/src/resources/attendance/attendanceControllers.js b/src/resources/attendance/attendanceControllers.js
index d2d9c94d1fa10c773d605f61c99ce81b81459a70..6561838748979edd9f0aaedeb246701a91c17df7 100644
--- a/src/resources/attendance/attendanceControllers.js
+++ b/src/resources/attendance/attendanceControllers.js
@@ -2,15 +2,17 @@ const { crudControllers } = require('../../utils/crud')
 const { Attendance } = require('./attendanceModel')
 const { pick } = require('lodash')
 
-const pickedKeys = ['_id', 'activity', 'user', 'state', 'comment']
+const pickedKeys = ['_id', 'activity', 'user', 'state', 'comments']
 
-exports.default = crudControllers(Attendance, pickedKeys)
+module.exports = crudControllers(Attendance, pickedKeys)
 
-exports.default.getOne = async (req, res) => {
+// On create update activity
+
+module.exports.getOne = async (req, res) => {
   try {
     const attendance = await Attendance.findOne({ _id: req.params.id })
       .populate('_user', ['_id', 'fullName', 'schacc'])
-      .populate('comment', ['creator', 'date', 'text'])
+      .populate('comments', ['creator', 'date', 'text'])
       .lean()
       .exec()
 
@@ -30,11 +32,11 @@ exports.default.getOne = async (req, res) => {
   }
 }
 
-exports.default.getMany = async (req, res) => {
+module.exports.getMany = async (req, res) => {
   try {
     const attendances = await Attendance.find()
       .populate('_user', ['_id', 'fullName', 'schacc'])
-      .populate('comment', ['creator', 'date', 'text'])
+      .populate('comments', ['creator', 'date', 'text'])
       .lean()
       .exec()
 
@@ -50,7 +52,7 @@ exports.default.getMany = async (req, res) => {
   }
 }
 
-exports.default.updateOne = async (req, res) => {
+module.exports.updateOne = async (req, res) => {
   try {
     const updatedAttendance = await Attendance.findOneAndUpdate(
       {
@@ -60,7 +62,7 @@ exports.default.updateOne = async (req, res) => {
       { new: true, runValidators: true }
     )
       .populate('_user', ['_id', 'fullName', 'schacc'])
-      .populate('comment', ['creator', 'date', 'text'])
+      .populate('comments', ['creator', 'date', 'text'])
       .lean()
       .exec()
 
diff --git a/src/resources/attendance/attendanceDocs.yml b/src/resources/attendance/attendanceDocs.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9dd6814942e54c9478b87f15c3b1fec44fc99353
--- /dev/null
+++ b/src/resources/attendance/attendanceDocs.yml
@@ -0,0 +1,113 @@
+openapi: '3.0.2'
+info:
+  title: 'Attendance Endpoint'
+  version: '1.0'
+
+paths:
+  /attendance:
+    get:
+      tags:
+        - 'Attendance'
+      summary: 'Get a List of attendances'
+      description: 'Have to be mentor for this.'
+      operationId: 'getAllAttendance'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: 'array'
+                items:
+                  $ref: '#/components/schemas/Attendance'
+    post:
+      tags:
+        - 'Attendance'
+      summary: 'Create an attendance'
+      description: 'Have to be mentor for this.'
+      operationId: 'createAttendance'
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Attendance'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Attendance'
+  /attendance/id/{id}:
+    get:
+      tags:
+        - 'Attendance'
+      summary: 'Get an attendance by ID'
+      description: 'Have to be mentor for this.'
+      operationId: 'getAttendance'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Attendance'
+    put:
+      tags:
+        - 'Attendance'
+      summary: 'Update an attendance by ID'
+      description: 'Only mentors can update an attendance.'
+      operationId: 'updateOneAttendance'
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Attendance'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Attendance'
+    delete:
+      tags:
+        - 'Attendance'
+      summary: 'Delete an attendance by ID'
+      description: 'Only mentors can delete an attendance.'
+      operationId: 'deleteAttendance'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Attendance'
+
+components:
+  schemas:
+    Attendance:
+      type: object
+      properties:
+        activity:
+          type: string
+          description: cuid of the activity
+        user:
+          type: string
+          description: schacc of the user
+        state:
+          type: string
+          enum:
+            - absent
+            - present
+            - cantcome
+          default: absent
+        comments:
+          type: array
+          items:
+            type: string
+            description: cuid of each comment
+      required:
+        - activity
+        - user
+        - state
diff --git a/src/resources/attendance/attendanceModel.js b/src/resources/attendance/attendanceModel.js
index 7cb4801958df1b12b59bd3d2184da26578c78350..ca827c82f3df9a07b526db1c28f4d42ee4593075 100644
--- a/src/resources/attendance/attendanceModel.js
+++ b/src/resources/attendance/attendanceModel.js
@@ -16,7 +16,7 @@ const AttendanceSchema = new mongoose.Schema(
       default: 'absent',
       required: true,
     },
-    comment: [
+    comments: [
       {
         type: mongoose.Schema.Types.ObjectId,
         ref: 'comment',
diff --git a/src/resources/attendance/attendanceRouter.js b/src/resources/attendance/attendanceRouter.js
index 5046a3fe167cd4c2f92ef33b7502c1d94a84cb13..aa2468a81b646a4029ccb579b3b6cec73e932e07 100644
--- a/src/resources/attendance/attendanceRouter.js
+++ b/src/resources/attendance/attendanceRouter.js
@@ -4,17 +4,17 @@ const { isLoggedIn, isMentor } = require('../../middlewares/auth')
 
 const router = Router()
 
-// /api/item
+// /api/v1/attendance/
 router
   .route('/')
-  .get(isLoggedIn, isMentor, controllers.default.getMany)
-  .post(isLoggedIn, isMentor, controllers.default.createOne)
+  .get(isLoggedIn, isMentor, controllers.getMany)
+  .post(isLoggedIn, isMentor, controllers.createOne)
 
-// /api/item/:id
+// /api/v1/attendance/id/:id
 router
-  .route('/:id')
-  .get(isLoggedIn, isMentor, controllers.default.getOne)
-  .put(isLoggedIn, isMentor, controllers.default.updateOne)
-  .delete(isLoggedIn, isMentor, controllers.default.removeOne)
+  .route('/id/:id')
+  .get(isLoggedIn, isMentor, controllers.getOne)
+  .put(isLoggedIn, isMentor, controllers.updateOne)
+  .delete(isLoggedIn, isMentor, controllers.removeOne)
 
 exports.default = router
diff --git a/src/resources/comment/__tests__/commentFuncTest.js b/src/resources/comment/__tests__/commentFuncTest.js
new file mode 100644
index 0000000000000000000000000000000000000000..8e3c54d6dac2bcf4a01f30a4d1c34f474f98df76
--- /dev/null
+++ b/src/resources/comment/__tests__/commentFuncTest.js
@@ -0,0 +1,247 @@
+const { app } = require('../../../server')
+const session = require('supertest-session')
+const { iteratee, merge, has } = require('lodash')
+
+const { validateKeys } = require('../../../utils/testHelpers')
+
+const { Comment } = require('../commentModel')
+const { Solution } = require('../../solution/solutionModel')
+const { Task } = require('../../task/taskModel')
+const { Attendance } = require('../../attendance/attendanceModel')
+const { Activity } = require('../../activity/activityModel')
+const { User } = require('../../user/userModel')
+
+const endpointUrl = '/api/v1/comment'
+
+const fakeUserJson = {
+  internal_id: 'fakeId',
+  schacc: 'fakeUser',
+  fullName: 'faker Janos',
+  secondaryEmail: 'faker@fake.com',
+}
+
+const fakeActivityJson = {
+  _id: '5f1351031185d36ad29687a3',
+  title: 'One title',
+  description: 'super desc',
+  date: '2020-01-01',
+  type: 'optional',
+}
+
+const fakeAttendanceJson = {
+  _id: '5f1351031185d36ad29687a4',
+  activity: '5f1351031185d36ad29687a3',
+  user: 'accepted_test',
+}
+
+const fakeTaskJson = {
+  _id: '5f1351031185d36ad29687a1',
+  title: 'One title',
+  description: 'super desc',
+  deadline: '2020-01-01',
+  bit: 1,
+  creator: 'mentor_test',
+  solutions: ['5f1351031185d36ad29687a2'],
+}
+
+const fakeSolutionJson = {
+  _id: '5f1351031185d36ad29687a2',
+  task: '5f1351031185d36ad29687a1',
+  title: 'One title',
+  description: 'super desc',
+  file: 'superfile.txt',
+  creator: 'accepted_test',
+}
+
+const fakeCommentOnSolutionJson = {
+  parentId: '5f1351031185d36ad29687a2',
+  parentType: 'solution',
+  text: 'alma',
+}
+
+const fakeCommentOnTaskJson = {
+  parentId: '5f1351031185d36ad29687a1',
+  parentType: 'task',
+  text: 'alma',
+}
+
+const fakeCommentOnAttendanceJson = {
+  parentId: '5f1351031185d36ad29687a4',
+  parentType: 'attendance',
+  text: 'alma',
+}
+
+const fakeCommentOnActivityJson = {
+  parentId: '5f1351031185d36ad29687a3',
+  parentType: 'activity',
+  text: 'alma',
+}
+
+describe('/comment "Mentor" Functionality', () => {
+  let authSession
+  // Login as mentor
+  beforeEach(async function (done) {
+    let testSession = session(app)
+    testSession.get(`/api/v1/login/mock/mentor`).end(function (err) {
+      if (err) return done(err)
+      authSession = testSession
+      return done()
+    })
+  })
+  // GET One
+  test(`GET returns with 404 if not found`, async () => {
+    let response = await authSession.get(
+      `${endpointUrl}/id/5f1351031185d36ad29687a1`
+    )
+    expect(response.statusCode).toBe(404)
+  })
+  test(`GET can get other users comment`, async () => {
+    await User.create(fakeUserJson)
+    await Activity.create(fakeActivityJson)
+    let comment = await Comment.create({
+      ...fakeCommentOnActivityJson,
+      creator: 'fakeUser',
+    })
+    let response = await authSession.get(`${endpointUrl}/id/${comment._id}`)
+    expect(response.statusCode).toBe(200)
+    expect(response.body.data.creator.schacc).toBe('fakeUser')
+  })
+  test(`GET anonym comment`, async () => {
+    await User.create(fakeUserJson)
+    await Activity.create(fakeActivityJson)
+    let comment = await Comment.create({
+      ...fakeCommentOnActivityJson,
+      creator: 'fakeUser',
+      isAnonim: true,
+    })
+    let response = await authSession.get(`${endpointUrl}/id/${comment._id}`)
+    expect(response.statusCode).toBe(200)
+    expect(response.body.data.creator).toBe('')
+  })
+  // Get Many
+  test(`GET many returns with all comments`, async () => {
+    await Activity.create(fakeActivityJson)
+    await Attendance.create(fakeAttendanceJson)
+    await Comment.create(fakeCommentOnActivityJson)
+    await Comment.create(fakeCommentOnAttendanceJson)
+    let response = await authSession.get(endpointUrl)
+    expect(response.statusCode).toBe(200)
+    expect(response.body.data.length).toBe(2)
+  })
+  // Create
+  test(`CREATE adds to parent (activity)`, async () => {
+    let activity = await Activity.create(fakeActivityJson)
+    let response = await authSession
+      .post(endpointUrl)
+      .send({ ...fakeCommentOnActivityJson, _id: '5f2801d8d5b36f6b39562cbb' })
+
+    expect(response.statusCode).toBe(200)
+    expect(response.body.data.parentId).toBe(String(activity._id))
+    let checkActivity = await Activity.findById(activity._id).lean().exec()
+    expect(String(checkActivity.comments[0])).toBe('5f2801d8d5b36f6b39562cbb')
+  })
+  // Delete
+  test(`DELETE a comment`, async () => {
+    let activity = await Activity.create(fakeActivityJson)
+    let response = await authSession
+      .post(endpointUrl)
+      .send({ ...fakeCommentOnActivityJson, _id: '5f2801d8d5b36f6b39562cbb' })
+
+    response = await authSession.delete(
+      `${endpointUrl}/id/5f2801d8d5b36f6b39562cbb`
+    )
+
+    expect(response.statusCode).toBe(200)
+  })
+  // Update
+  test(`UPDATE a comment`, async () => {
+    let activity = await Activity.create(fakeActivityJson)
+    let response = await authSession
+      .post(endpointUrl)
+      .send({ ...fakeCommentOnActivityJson, _id: '5f2801d8d5b36f6b39562cbb' })
+
+    response = await authSession
+      .put(`${endpointUrl}/id/5f2801d8d5b36f6b39562cbb`)
+      .send({ creator: 'almafa', text: 'kortefa' })
+
+    expect(response.statusCode).toBe(200)
+    expect(response.body.data.creator).not.toBe('almafa')
+    expect(response.body.data.text).toBe('kortefa')
+  })
+})
+describe('/comment "Accepted" Functionality', () => {
+  let authSession
+  // Login as accepted
+  beforeEach(async function (done) {
+    let testSession = session(app)
+    testSession.get(`/api/v1/login/mock/accepted`).end(function (err) {
+      if (err) return done(err)
+      authSession = testSession
+      return done()
+    })
+  })
+  // GET One
+  test(`GET cant get comment on Attendance or Activity`, async () => {
+    await User.create(fakeUserJson)
+    await Activity.create(fakeActivityJson)
+    await Attendance.create(fakeAttendanceJson)
+    let commentOnActivity = await Comment.create(fakeCommentOnActivityJson)
+    let commentonAttendance = await Comment.create(fakeCommentOnAttendanceJson)
+    let response = await authSession.get(
+      `${endpointUrl}/id/${commentOnActivity._id}`
+    )
+    expect(response.statusCode).toBe(403)
+    response = await authSession.get(
+      `${endpointUrl}/id/${commentonAttendance._id}`
+    )
+    expect(response.statusCode).toBe(403)
+    let ownCommentOnActivity = await Comment.create({
+      ...fakeCommentOnActivityJson,
+      creator: 'accepted_test',
+    })
+    response = await authSession.get(
+      `${endpointUrl}/id/${ownCommentOnActivity._id}`
+    )
+    expect(response.statusCode).toBe(403)
+  })
+  test(`GET comment on own Solution`, async () => {
+    await User.create(fakeUserJson)
+    await Task.create(fakeTaskJson)
+    await Solution.create({ ...fakeSolutionJson, creator: 'accepted_test' })
+    let commentOnSolution = await Comment.create(fakeCommentOnSolutionJson)
+    let response = await authSession.get(
+      `${endpointUrl}/id/${commentOnSolution._id}`
+    )
+    expect(response.statusCode).toBe(200)
+    let owncommentOnSolution = await Comment.create({
+      ...fakeCommentOnSolutionJson,
+      creator: 'accepted_test',
+    })
+    response = await authSession.get(
+      `${endpointUrl}/id/${owncommentOnSolution._id}`
+    )
+    expect(response.statusCode).toBe(200)
+  })
+  test(`GET comment on others Solution`, async () => {
+    await User.create(fakeUserJson)
+    await Task.create(fakeTaskJson)
+    await Solution.create({ ...fakeSolutionJson, creator: 'jani' })
+    let commentOnSolution = await Comment.create({
+      ...fakeCommentOnSolutionJson,
+    })
+    let response = await authSession.get(
+      `${endpointUrl}/id/${commentOnSolution._id}`
+    )
+    expect(response.statusCode).toBe(403)
+    let owncommentOnSolution = await Comment.create({
+      ...fakeCommentOnSolutionJson,
+      creator: 'accepted_test',
+    })
+    response = await authSession.get(
+      `${endpointUrl}/id/${owncommentOnSolution._id}`
+    )
+    expect(response.statusCode).toBe(403)
+  })
+  // Create
+  // TODO
+})
diff --git a/src/resources/comment/__tests__/commentPermTest.js b/src/resources/comment/__tests__/commentPermTest.js
new file mode 100644
index 0000000000000000000000000000000000000000..de634696ed272aa0455c66cb5c453f23b52abefa
--- /dev/null
+++ b/src/resources/comment/__tests__/commentPermTest.js
@@ -0,0 +1,45 @@
+const { app } = require('../../../server')
+const { crudPermTest } = require('../../../utils/testHelpers')
+
+const { Comment } = require('../commentModel')
+
+const endpointUrl = '/api/v1/comment'
+
+const fakeCommentJson = {
+  parentId: '5f1351031185d36ad29687a2',
+  parentType: 'solution',
+  text: 'alma',
+}
+
+describe('/comment Permission tests', () => {
+  crudPermTest(
+    app,
+    endpointUrl + '/id',
+    Comment,
+    'comment',
+    fakeCommentJson,
+    [false, false, true, true, true],
+    [
+      // [role, create, readAll, readOne, update, delete]
+      ['none', false, false, false, false, false],
+      ['normal', false, false, false, false, false],
+      ['accepted', true, false, true, false, false], // can update or delete own
+      ['mentor', true, true, true, true, true],
+    ]
+  )
+  crudPermTest(
+    app,
+    endpointUrl,
+    Comment,
+    'comment',
+    fakeCommentJson,
+    [true, true, false, false, false],
+    [
+      // [role, create, readAll, readOne, update, delete]
+      ['none', false, false, false, false, false],
+      ['normal', false, false, false, false, false],
+      ['accepted', true, false, true, false, false],
+      ['mentor', true, true, true, true, true],
+    ]
+  )
+})
diff --git a/src/resources/comment/commentControllers.js b/src/resources/comment/commentControllers.js
index aec82b07861967c7a5a7d9a1fbff3178ddadf0aa..1b1d3b7555a5cccacddb6e40bf09d4c1b7e91b69 100644
--- a/src/resources/comment/commentControllers.js
+++ b/src/resources/comment/commentControllers.js
@@ -1,4 +1,259 @@
 const { crudControllers } = require('../../utils/crud')
+const { pick } = require('lodash')
+
 const { Comment } = require('./commentModel')
+const { Solution } = require('../solution/solutionModel')
+const { Task } = require('../task/taskModel')
+const { Attendance } = require('../attendance/attendanceModel')
+const { Activity } = require('../activity/activityModel')
+
+const pickedKeys = [
+  '_id',
+  'parentId',
+  'parentType',
+  'creator',
+  'text',
+  'createdAt',
+  'updatedAt',
+]
+
+exports.default = crudControllers(Comment, pickedKeys)
+
+function getParentModel(comment) {
+  switch (comment.parentType) {
+    case 'solution':
+      return Solution
+    case 'task':
+      return Task
+    case 'attendance':
+      return Attendance
+    case 'activity':
+      return Activity
+    default:
+      throw { message: `Invalid Parent Type: ${comment.parentType}` }
+  }
+}
+
+exports.default.getOne = async (req, res) => {
+  try {
+    const comment = await Comment.findOne({
+      _id: req.params.id,
+    })
+      .populate('_creator', ['fullName', 'nickName', 'schacc'])
+      .lean()
+      .exec()
+
+    if (!comment) return res.status(404).end()
+
+    if (
+      (comment.parentType == 'attendance' ||
+        comment.parentType == 'activity') &&
+      req.user.role !== 'mentor'
+    )
+      return res
+        .status(403)
+        .json({ messages: ['You cannot get other users comment.'] })
+        .end()
+
+    if (req.user.role !== 'mentor') {
+      // Check if own solution
+      if (comment.parentType == 'solution') {
+        const solution = await Solution.findById(comment.parentId).lean().exec()
+        if (!solution)
+          return res
+            .status(404)
+            .json({ messages: ["Parent Object doesn't exist!"] })
+
+        if (solution.creator != req.user.schacc)
+          return res
+            .status(403)
+            .json({ messages: ['You cannot get other users comment.'] })
+            .end()
+      }
+    }
+
+    comment.creator = comment._creator
+    if (comment.isAnonim) comment.creator = ''
+
+    return res
+      .status(200)
+      .json({ data: pick(comment, pickedKeys) })
+      .end()
+  } catch (err) {
+    if (err.name == 'ValidationError') {
+      // Throwed by Mongoose
+      let messages = []
+      for (field in err.errors) {
+        messages.push(err.errors[field].message)
+      }
+      return res.status(422).json({ messages })
+    }
+    console.error(err)
+    return res.status(500).json({ message: err.message })
+  }
+}
+
+exports.default.getMany = async (req, res) => {
+  try {
+    const comments = await Comment.find()
+      .populate('_creator', 'fullName nickName schacc')
+      .select(['-__v'])
+      .lean()
+      .exec()
+
+    return res
+      .status(200)
+      .json({
+        data: comments.map((e) => {
+          if (e.isAnonim) e.creator = ''
+          else e.creator = e._creator
+          return pick(e, pickedKeys)
+        }),
+      })
+      .end()
+  } catch (err) {
+    if (err.name == 'ValidationError') {
+      // Throwed by Mongoose
+      let messages = []
+      for (field in err.errors) {
+        messages.push(err.errors[field].message)
+      }
+      return res.status(422).json({ messages })
+    }
+    console.error(err)
+    return res.status(500).json({ message: err.message })
+  }
+}
+
+exports.default.createOne = async (req, res) => {
+  try {
+    if (req.user.role != 'mentor' && !req.body.creator)
+      req.body.creator = req.user.schacc
+
+    let comment = await Comment.create({
+      ...req.body,
+    })
+
+    // Add to parent
+    let updateParent = await getParentModel(comment).findById(comment.parentId)
+    if (!updateParent) {
+      await Comment.findByIdAndRemove(comment._id).lean().exec()
+      return res
+        .status(404)
+        .json({ messages: ["Parent Object doesn't exist!"] })
+    }
+    if (updateParent.comments.indexOf(comment._id) == -1) {
+      updateParent.comments.push(comment._id)
+      try {
+        await updateParent.save()
+      } catch (error) {
+        await Comment.findByIdAndRemove(comment._id)
+      }
+    }
+
+    comment = await comment
+      .populate('_creator', 'fullName nickName schacc')
+      .execPopulate()
+
+    let retComment = comment.toObject()
+    retComment.creator = retComment._creator
+
+    if (retComment.isAnonim) retComment.creator = ''
+
+    return res
+      .status(200)
+      .json({
+        data: pick(retComment, pickedKeys),
+      })
+      .end()
+  } catch (err) {
+    if (err.name == 'ValidationError') {
+      // Throwed by Mongoose
+      let messages = []
+      for (field in err.errors) {
+        messages.push(err.errors[field].message)
+      }
+      return res.status(422).json({ messages })
+    }
+    console.error(err)
+    return res.status(500).json({ message: err.message })
+  }
+}
+
+exports.default.updateOne = async (req, res) => {
+  try {
+    const comment = await Comment.findById(req.params.id).lean().exec()
+
+    if (!comment) return res.status(404).end()
+
+    if (comment.creator !== req.user.schacc && req.user.role != 'mentor')
+      return res
+        .status(403)
+        .json({ messages: ['You cannot update other users comment.'] })
+        .end()
+
+    const updatedComment = await Comment.findOneAndUpdate(
+      { _id: req.params.id },
+      { text: req.body.text },
+      { new: true }
+    )
+      .lean()
+      .exec()
+
+    if (updatedComment.isAnonim) updatedComment.creator = ''
+
+    return res.status(200).json({ data: pick(updatedComment, pickedKeys) })
+  } catch (err) {
+    if (err.name == 'ValidationError') {
+      // Throwed by Mongoose
+      let messages = []
+      for (field in err.errors) {
+        messages.push(err.errors[field].message)
+      }
+      return res.status(422).json({ messages })
+    }
+    console.error(err)
+    return res.status(500).json({ message: err.message })
+  }
+}
+
+exports.default.removeOne = async (req, res) => {
+  try {
+    const comment = await Comment.findById({ _id: req.params.id }).lean().exec()
+
+    if (comment.creator !== req.user.schacc && req.user.role != 'mentor')
+      return res
+        .status(403)
+        .json({ messages: ['You cannot delete other users comment.'] })
+        .end()
+
+    const removed = await Comment.findByIdAndRemove({ _id: req.params.id })
+    if (!removed) {
+      return res.status(404).end()
+    }
+
+    // remove from parent model
+    await getParentModel(removed).updateMany(
+      {},
+      { $pull: { comments: { $in: removed._id } } }
+    )
+
+    if (removed.isAnonim) removed.creator = ''
 
-exports.default = crudControllers(Comment)
+    return res
+      .status(200)
+      .json({ data: pick(removed, pickedKeys) })
+      .end()
+  } catch (err) {
+    if (err.name == 'ValidationError') {
+      // Throwed by Mongoose
+      let messages = []
+      for (field in err.errors) {
+        messages.push(err.errors[field].message)
+      }
+      return res.status(422).json({ messages })
+    }
+    console.error(err)
+    return res.status(500).json({ message: err.message })
+  }
+}
diff --git a/src/resources/comment/commentDocs.yml b/src/resources/comment/commentDocs.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a9a3ea2b8ff5b9ec33517bbfdaf83c788f791912
--- /dev/null
+++ b/src/resources/comment/commentDocs.yml
@@ -0,0 +1,127 @@
+openapi: '3.0.2'
+info:
+  title: 'Comment Endpoint'
+  version: '1.0'
+
+paths:
+  /comment:
+    get:
+      tags:
+        - 'Comment'
+      summary: 'Get a List of comments'
+      description: 'This can only be get by a mentor.'
+      operationId: 'getAllComments'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: 'array'
+                items:
+                  $ref: '#/components/schemas/Comment'
+    post:
+      tags:
+        - 'Comment'
+      summary: 'Create a comment'
+      description: 'Only logged in users can create a comment.
+        The creator only can be set by Mentor.
+        By default the creator is own user.
+        Automatically adds itself to parent object.'
+      operationId: 'createComment'
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Comment'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Comment'
+  /comment/id/{id}:
+    get:
+      tags:
+        - 'Comment'
+      summary: 'Get a comment by ID'
+      description: 'If not mentor only own comment
+        or comment on own solution can be get.'
+      operationId: 'getComment'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Comment'
+    delete:
+      tags:
+        - 'Comment'
+      summary: 'Delete a comment by ID'
+      description: 'Only logged in users can delete a comment.
+        To delete has to be the owner or mentor.'
+      operationId: 'deleteComment'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Comment'
+    put:
+      tags:
+        - 'Comment'
+      summary: 'Update a comment by ID'
+      description: 'Only logged in users can update a comment.
+        To update has to be the owner or mentor.'
+      operationId: 'updateOneComment'
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Comment'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Groups'
+
+components:
+  schemas:
+    Comment:
+      type: object
+      properties:
+        parentId:
+          type: string
+          description: ObjectId of the object that has the comment
+        parentType:
+          type: string
+          enum:
+            - 'solution'
+            - 'task'
+            - 'attendance'
+            - 'activity'
+          description: Name of the object that has the comment
+        creator:
+          type: string
+          description: Schacc of the creator. Default is own user
+        text:
+          type: string
+        isAnonim:
+          type: boolean
+          default: false
+        createdAt:
+          type: string
+          format: date-time
+        updatedAt:
+          type: string
+          format: date-time
+      required:
+        - parentId
+        - parentType
+        - text
+        - isAnonim
diff --git a/src/resources/comment/commentModel.js b/src/resources/comment/commentModel.js
index de782a9ad446e26e80493f5e21e8575fd220b51d..6bdcd7057ba98898b552c18fe39829528a530701 100644
--- a/src/resources/comment/commentModel.js
+++ b/src/resources/comment/commentModel.js
@@ -2,6 +2,16 @@ const mongoose = require('mongoose')
 
 const CommentSchema = new mongoose.Schema(
   {
+    parentId: {
+      // can be an objectId (no ref)
+      type: mongoose.Schema.Types.ObjectId,
+      required: true,
+    },
+    parentType: {
+      type: String,
+      required: true,
+      enum: ['solution', 'task', 'attendance', 'activity'],
+    },
     creator: {
       type: String,
     },
@@ -9,9 +19,10 @@ const CommentSchema = new mongoose.Schema(
       type: String,
       required: true,
     },
-    date: {
-      type: Date,
+    isAnonim: {
+      type: Boolean,
       required: true,
+      default: false,
     },
   },
   { timestamps: true }
diff --git a/src/resources/comment/commentRouter.js b/src/resources/comment/commentRouter.js
index f5cb84a37c3648fb59b7d895200ca90c2e6b5eb8..f1711782e830e09505b64b451d00e73e82141cc5 100644
--- a/src/resources/comment/commentRouter.js
+++ b/src/resources/comment/commentRouter.js
@@ -1,19 +1,24 @@
 const { Router } = require('express')
 const controllers = require('./commentControllers')
+const {
+  isLoggedIn,
+  isMentor,
+  isAcceptedOrMentor,
+} = require('../../middlewares/auth')
 
 const router = Router()
 
-// /api/item
+// /api/v1/comment
 router
   .route('/')
-  .get(controllers.default.getMany)
-  .post(controllers.default.createOne)
+  .get(isLoggedIn, isMentor, controllers.default.getMany)
+  .post(isLoggedIn, isAcceptedOrMentor, controllers.default.createOne)
 
-// /api/item/:id
+// /api/v1/comment/id/:id
 router
-  .route('/:id')
-  .get(controllers.default.getOne)
-  .put(controllers.default.updateOne)
-  .delete(controllers.default.removeOne)
+  .route('/id/:id')
+  .get(isLoggedIn, isAcceptedOrMentor, controllers.default.getOne)
+  .put(isLoggedIn, isAcceptedOrMentor, controllers.default.updateOne)
+  .delete(isLoggedIn, isAcceptedOrMentor, controllers.default.removeOne)
 
 exports.default = router
diff --git a/src/resources/extra/extraRouter.js b/src/resources/extra/extraRouter.js
deleted file mode 100644
index 7508feb41bc0fe9f8da7ef6e0805c4dc4fa4ffbe..0000000000000000000000000000000000000000
--- a/src/resources/extra/extraRouter.js
+++ /dev/null
@@ -1,19 +0,0 @@
-const { Router } = require('express')
-const { isLoggedIn } = require('../../middlewares/auth')
-const { getOne, updateOne } = require('../user/userControllers').default
-
-const router = Router()
-
-// /api/v1/extra/me
-router
-  .route('/me') // Tested in user
-  .get(isLoggedIn, async (req, res) => {
-    req.params.id = req.user.schacc
-    await getOne(req, res)
-  })
-  .put(isLoggedIn, async (req, res) => {
-    req.params.id = req.user.schacc
-    await updateOne(req, res)
-  })
-
-exports.default = router
diff --git a/src/resources/groups/__tests__/groupsFuncTest.js b/src/resources/groups/__tests__/groupsFuncTest.js
index 7f652dd6c919eea22044f5baa04105716de9a8e2..89cf4f82156c096a56dc49739f573167fa9ee753 100644
--- a/src/resources/groups/__tests__/groupsFuncTest.js
+++ b/src/resources/groups/__tests__/groupsFuncTest.js
@@ -13,7 +13,7 @@ const fakeGroupsJson = {
 }
 
 const defaultKeys = {
-  _id: true,
+  _id: false,
   name: true,
   description: true,
   groupPath: true,
@@ -33,7 +33,7 @@ describe('/group "Mentor" Functionality', () => {
   // GET One
   test(`GET one returns with allowed keys`, async () => {
     const newGroup = await Groups.create(fakeGroupsJson)
-    let response = await authSession.get(`${endpointUrl}/${newGroup._id}`)
+    let response = await authSession.get(`${endpointUrl}/${newGroup.name}`)
     expect(response.statusCode).toBe(200)
     validateKeys(response.body.data, defaultKeys)
   })
@@ -56,7 +56,7 @@ describe('/group "Mentor" Functionality', () => {
   // Delete
   test(`Delete returns with allowed keys`, async () => {
     const newGroup = await Groups.create(fakeGroupsJson)
-    let response = await authSession.delete(`${endpointUrl}/${newGroup._id}`)
+    let response = await authSession.delete(`${endpointUrl}/${newGroup.name}`)
     expect(response.statusCode).toBe(200)
     validateKeys(response.body.data, defaultKeys)
   })
@@ -64,7 +64,7 @@ describe('/group "Mentor" Functionality', () => {
   test(`Update returns with allowed keys`, async () => {
     const newGroup = await Groups.create(fakeGroupsJson)
     let response = await authSession
-      .put(`${endpointUrl}/${newGroup._id}`)
+      .put(`${endpointUrl}/${newGroup.name}`)
       .send({
         name: 'almafa',
       })
diff --git a/src/resources/groups/groupsControllers.js b/src/resources/groups/groupsControllers.js
index 74c23cf2e260bbc73fea57f31c330b309e1cafee..bf65110e3013786bb1f82c7cdff8d2f79a393fb8 100644
--- a/src/resources/groups/groupsControllers.js
+++ b/src/resources/groups/groupsControllers.js
@@ -1,19 +1,67 @@
-const { crudControllers } = require('../../utils/crud')
+const { crudControllers, createOne } = require('../../utils/crud')
 const { Groups } = require('./groupsModel')
 const { Application } = require('../application/applicationModel')
 const { pick } = require('lodash')
 
-exports.default = crudControllers(Groups, [
-  '_id',
-  'name',
-  'description',
-  'groupPath',
-])
+const pickedKeys = ['name', 'description', 'groupPath']
 
-exports.default.removeOne = async (req, res) => {
+module.exports = crudControllers(Groups, pickedKeys)
+
+module.exports.getOne = async (req, res) => {
+  try {
+    const group = await Groups.findOne({ name: req.params.groupName })
+      .lean()
+      .exec()
+
+    if (!group) {
+      return res.status(404).end()
+    }
+    res.status(200).json({ data: pick(group, pickedKeys) })
+  } catch (err) {
+    if (err.name == 'CastError') {
+      return res.status(422).json('Invalid ID provided')
+    } else {
+      console.error(err)
+      res.status(400).end()
+    }
+  }
+}
+
+module.exports.updateOne = async (req, res) => {
+  try {
+    const updatedGroup = await Groups.findOneAndUpdate(
+      {
+        name: req.params.groupName,
+      },
+      req.body,
+      { new: true, runValidators: true }
+    )
+      .lean()
+      .exec()
+
+    if (!updatedGroup) {
+      return res.status(404).end()
+    }
+
+    res.status(200).json({ data: pick(updatedGroup, pickedKeys) })
+  } catch (err) {
+    if (err.name == 'ValidationError') {
+      let messages = []
+      for (field in err.errors) {
+        messages.push(err.errors[field].message)
+      }
+      res.status(422).json({ messages })
+    } else {
+      console.error(err)
+      res.status(400).end()
+    }
+  }
+}
+
+module.exports.removeOne = async (req, res) => {
   try {
     const removed = await Groups.findOneAndRemove({
-      _id: req.params.id,
+      name: req.params.groupName,
     })
 
     if (!removed) {
@@ -22,11 +70,9 @@ exports.default.removeOne = async (req, res) => {
 
     Application.updateMany({}, { $pull: { groups: { $in: removed._id } } })
 
-    return res
-      .status(200)
-      .json({
-        data: pick(removed, ['_id', 'name', 'description', 'groupPath']),
-      })
+    return res.status(200).json({
+      data: pick(removed, pickedKeys),
+    })
   } catch (e) {
     console.error(e)
     return res.status(400).end()
diff --git a/src/resources/groups/groupsDocs.yml b/src/resources/groups/groupsDocs.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b7d468e19cd20832fe99390390fa2bd6966fe54f
--- /dev/null
+++ b/src/resources/groups/groupsDocs.yml
@@ -0,0 +1,101 @@
+openapi: '3.0.2'
+info:
+  title: 'Groups Endpoint'
+  version: '1.0'
+
+paths:
+  /groups:
+    get:
+      tags:
+        - 'Groups'
+      summary: 'Get a List of groups'
+      description: 'Avaliable to anyone.'
+      operationId: 'getAllGroups'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: 'array'
+                items:
+                  $ref: '#/components/schemas/Groups'
+    post:
+      tags:
+        - 'Groups'
+      summary: 'Create a group'
+      description: 'This can only be done by a mentor.'
+      operationId: 'createGroup'
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Groups'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Groups'
+  /groups/{name}:
+    get:
+      tags:
+        - 'Groups'
+      summary: 'Get a group by name'
+      description: 'Avaliable to anyone.'
+      operationId: 'getOneGroup'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Groups'
+    put:
+      tags:
+        - 'Groups'
+      summary: 'Update a Group by name'
+      description: 'This can only be done by a mentor.'
+      operationId: 'updateOneGroup'
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Groups'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Groups'
+    delete:
+      tags:
+        - 'Groups'
+      summary: 'Delete Group by name'
+      description: 'This can only be done by a mentor.'
+      operationId: 'deleteOneGroup'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Groups'
+
+components:
+  schemas:
+    Groups:
+      type: object
+      properties:
+        name:
+          type: string
+        description:
+          type: string
+        groupPath:
+          type: string
+      required:
+        - name
+        - description
+        - groupPath
diff --git a/src/resources/groups/groupsModel.js b/src/resources/groups/groupsModel.js
index 4fa47345a87903dbff26f6c5b7c13787329e4eb9..c3dc1c442db5b0b1bdce38bd21a4b543a3dc02a3 100644
--- a/src/resources/groups/groupsModel.js
+++ b/src/resources/groups/groupsModel.js
@@ -4,6 +4,7 @@ const GroupsSchema = new mongoose.Schema({
   name: {
     type: String,
     required: true,
+    index: { unique: true },
   },
   description: {
     type: String,
@@ -15,9 +16,6 @@ const GroupsSchema = new mongoose.Schema({
   },
 })
 
-// Careful with the docs, there are some deprecated ones
-// https://mongoosejs.com/docs/guide.html
-
 const Groups = mongoose.model('groups', GroupsSchema)
 
 exports.Groups = Groups
diff --git a/src/resources/groups/groupsRouter.js b/src/resources/groups/groupsRouter.js
index 5d00212fc9fdc8454cd09a85415a5d468bc2cffd..16902eecdecdf14a2c260ad3f06278f03b8d5b52 100644
--- a/src/resources/groups/groupsRouter.js
+++ b/src/resources/groups/groupsRouter.js
@@ -5,17 +5,17 @@ const { isLoggedIn, isMentor } = require('../../middlewares/auth')
 
 const router = Router()
 
-// /api/groups
+// /api/v1/groups
 router
   .route('/')
-  .get(controllers.default.getMany)
-  .post(isLoggedIn, isMentor, controllers.default.createOne)
+  .get(controllers.getMany)
+  .post(isLoggedIn, isMentor, controllers.createOne)
 
-// /api/groups/:id
+// /api/v1/groups/:groupName
 router
-  .route('/:id')
-  .get(controllers.default.getOne)
-  .put(isLoggedIn, isMentor, controllers.default.updateOne)
-  .delete(isLoggedIn, isMentor, controllers.default.removeOne)
+  .route('/:groupName')
+  .get(controllers.getOne)
+  .put(isLoggedIn, isMentor, controllers.updateOne)
+  .delete(isLoggedIn, isMentor, controllers.removeOne)
 
 exports.default = router
diff --git a/src/resources/mentor/__tests__/mentorFuncTest.js b/src/resources/mentor/__tests__/mentorFuncTest.js
new file mode 100644
index 0000000000000000000000000000000000000000..ac116aea0e867783b39fbc4d1ac91817edf3982f
--- /dev/null
+++ b/src/resources/mentor/__tests__/mentorFuncTest.js
@@ -0,0 +1,122 @@
+const { app } = require('../../../server')
+const session = require('supertest-session')
+const { merge, has } = require('lodash')
+const { validateKeys } = require('../../../utils/testHelpers')
+
+const { User } = require('../../user/userModel')
+const { Mentor } = require('../mentorModel')
+
+const endpointUrl = '/api/v1/mentor'
+const fakeUserJson = {
+  internal_id: 'fakeId',
+  schacc: 'fakeUser',
+  fullName: 'faker Janos',
+  secondaryEmail: 'faker@fake.com',
+}
+let fakeMentorsJson = {
+  user: fakeUserJson.schacc,
+  description: 'Legjobb mentor ever',
+}
+const defaultKeys = {
+  _id: true,
+  user: true,
+  description: true,
+}
+
+describe('/mentor "Mentor" Functionality', () => {
+  let authSession
+  // Login as mentor
+  beforeEach(async function (done) {
+    let testSession = session(app)
+    testSession.get(`/api/v1/login/mock/mentor`).end(function (err) {
+      if (err) return done(err)
+      authSession = testSession
+      return done()
+    })
+  })
+  //readone
+  test(`GET existing mentor`, async () => {
+    const newMentor = await Mentor.create(fakeMentorsJson)
+    let response = await authSession.get(`${endpointUrl}/id/${newMentor._id}`)
+    expect(response.statusCode).toBe(200)
+  })
+  test('GET invalid mentor', async () => {
+    let response = await authSession.get(`${endpointUrl}/id/almafa`)
+    expect(response.statusCode).toBe(422)
+  })
+  // Get Many
+  test(`GET many returns with allowed keys`, async () => {
+    await Mentor.create(fakeMentorsJson)
+    await Mentor.create(fakeMentorsJson)
+    let response = await authSession.get(endpointUrl)
+    expect(response.statusCode).toBe(200)
+    response.body.data.forEach((eachData) => {
+      validateKeys(eachData, defaultKeys)
+    })
+  })
+  // Create
+  test(`Create mentor`, async () => {
+    const newUser = await User.create(fakeUserJson)
+    const newMentor = await Mentor.create(fakeMentorsJson)
+    let response = await authSession.post(`${endpointUrl}/`).send({
+      user: newUser.schacc,
+      description: 'Legjobb mentor ever',
+    })
+    expect(response.statusCode).toBe(201)
+    validateKeys(response.body.data, defaultKeys)
+  })
+  //Update
+  test(`Update mentor`, async () => {
+    const newMentor = await Mentor.create(fakeMentorsJson)
+    let response = await authSession
+      .put(`${endpointUrl}/id/${newMentor._id}`)
+      .send({
+        description: 'updateddescription',
+      })
+    expect(response.statusCode).toBe(200)
+    expect(response.body.data.description).toBe('updateddescription')
+  })
+  //Delete
+  test(`Delete mentor`, async () => {
+    const newMentor = await Mentor.create(fakeMentorsJson)
+    let response = await authSession.delete(
+      `${endpointUrl}/id/${newMentor._id}`
+    )
+    expect(response.statusCode).toBe(200)
+  })
+})
+//Nem számít az ,hogy melyikkel teszteled mert mind2nak ugyan olyannak kell lennie.
+//normal=accepted
+describe('/mentor "Accepted" Functionality', () => {
+  let authSession
+  // Login as accepted and create a group
+  beforeEach(async function (done) {
+    let testSession = session(app)
+    testSession.get(`/api/v1/login/mock/accepted`).end(function (err) {
+      if (err) return done(err)
+      authSession = testSession
+      return done()
+    })
+  })
+  //readone
+  test(`GET existing mentor`, async () => {
+    const newUser = await User.create(fakeUserJson)
+    const newMentor = await Mentor.create(fakeMentorsJson)
+    let response = await authSession.get(`${endpointUrl}/id/${newMentor._id}`)
+    expect(response.statusCode).toBe(200)
+  })
+  test('GET invalid mentor', async () => {
+    let response = await authSession.get(`${endpointUrl}/id/almafa`)
+    expect(response.statusCode).toBe(422)
+  })
+  // Get Many
+  test(`GET many returns with allowed keys`, async () => {
+    await Mentor.create(fakeMentorsJson)
+    await Mentor.create(fakeMentorsJson)
+    let response = await authSession.get(endpointUrl)
+    expect(response.statusCode).toBe(200)
+    response.body.data.forEach((eachData) => {
+      validateKeys(eachData, defaultKeys)
+    })
+  })
+})
diff --git a/src/resources/mentor/__tests__/mentorPermTest.js b/src/resources/mentor/__tests__/mentorPermTest.js
index e2edcc6933f692f6052eaf6a4e704dec87755673..9618c35560e0c69d05b74999133edce6e6d362e5 100644
--- a/src/resources/mentor/__tests__/mentorPermTest.js
+++ b/src/resources/mentor/__tests__/mentorPermTest.js
@@ -11,13 +11,28 @@ const fakeMentorJson = {
 }
 
 describe('/mentor Permission tests', () => {
+  crudPermTest(
+    app,
+    endpointUrl + '/id',
+    Mentor,
+    'mentor',
+    fakeMentorJson,
+    [false, false, true, true, true],
+    [
+      // [role, create, readAll, readOne, update, delete]
+      ['none', false, false, false, false, false],
+      ['normal', false, true, true, false, false],
+      ['accepted', false, true, true, false, false],
+      ['mentor', true, true, true, true, true],
+    ]
+  )
   crudPermTest(
     app,
     endpointUrl,
     Mentor,
     'mentor',
     fakeMentorJson,
-    [true, true, true, true, true],
+    [true, true, false, false, false],
     [
       // [role, create, readAll, readOne, update, delete]
       ['none', false, false, false, false, false],
diff --git a/src/resources/mentor/mentorControllers.js b/src/resources/mentor/mentorControllers.js
index d20349e8593659b6745b9a67d222e9f5709311df..4da413f67440c53ede0c0503e471a75448991a1c 100644
--- a/src/resources/mentor/mentorControllers.js
+++ b/src/resources/mentor/mentorControllers.js
@@ -23,11 +23,10 @@ exports.default.getOne = async (req, res) => {
   } catch (err) {
     if (err.name === 'CastError') {
       // Throwed by Mongoose
-      console.error(err)
       return res.status(422).json({ message: 'Invalid ID provided' })
     }
     console.error(err)
-    res.status(400).end()
+    res.status(500).end()
   }
 }
 exports.default.getMany = async (req, res) => {
@@ -47,7 +46,7 @@ exports.default.getMany = async (req, res) => {
     })
   } catch (err) {
     console.error(err)
-    return res.status(400).end()
+    return res.status(500).end()
   }
 }
 exports.default.createOne = async (req, res) => {
@@ -69,6 +68,6 @@ exports.default.createOne = async (req, res) => {
     }
 
     console.error(err)
-    return res.status(400).end()
+    return res.status(500).end()
   }
 }
diff --git a/src/resources/mentor/mentorDocs.yml b/src/resources/mentor/mentorDocs.yml
new file mode 100644
index 0000000000000000000000000000000000000000..14669b5cb32f20c2f6230b6907594c5ea74f66a0
--- /dev/null
+++ b/src/resources/mentor/mentorDocs.yml
@@ -0,0 +1,99 @@
+openapi: '3.0.2'
+info:
+  title: 'Mentor Endpoint'
+  version: '1.0'
+
+paths:
+  /mentor:
+    get:
+      tags:
+        - 'Mentor'
+      summary: 'Get a List of mentors'
+      description: 'Have to be logged in.'
+      operationId: 'getAllMentor'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: 'array'
+                items:
+                  $ref: '#/components/schemas/Mentor'
+    post:
+      tags:
+        - 'Mentor'
+      summary: 'Create a mentor'
+      description: 'Have to be mentor for this.'
+      operationId: 'createMentor'
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Mentor'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Mentor'
+  /mentor/id/{id}:
+    get:
+      tags:
+        - 'Mentor'
+      summary: 'Get a mentor by ID'
+      description: 'Have to be logged in for this.'
+      operationId: 'getMentor'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Mentor'
+    put:
+      tags:
+        - 'Mentor'
+      summary: 'Update a mentor by ID'
+      description: 'Only mentors can update a mentor.'
+      operationId: 'updateOneMentor'
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Mentor'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Mentor'
+    delete:
+      tags:
+        - 'Mentor'
+      summary: 'Delete a mentor by ID'
+      description: 'Only mentors can delete a mentor.'
+      operationId: 'deleteMentor'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Mentor'
+
+components:
+  schemas:
+    Mentor:
+      type: object
+      properties:
+        user:
+          type: string
+          description: schacc of the user
+        description:
+          type: string
+      required:
+        - user
+        - description
diff --git a/src/resources/mentor/mentorModel.js b/src/resources/mentor/mentorModel.js
index 6e7bcc13fa99c18ff5cdef3bb92624010d657196..a442bb8f2f7c2af09b328c01d091b30a3d2cbe95 100644
--- a/src/resources/mentor/mentorModel.js
+++ b/src/resources/mentor/mentorModel.js
@@ -2,8 +2,7 @@ const mongoose = require('mongoose')
 
 const MentorSchema = new mongoose.Schema({
   user: {
-    type: mongoose.Schema.Types.ObjectId,
-    ref: 'user',
+    type: String,
     required: true,
   },
   description: {
diff --git a/src/resources/mentor/mentorRouter.js b/src/resources/mentor/mentorRouter.js
index 860a015d3e787de86be115e0bbad955f98ca0eb5..a3f0c19d8abe5f4f73a33af0ab645776ebc5aa9f 100644
--- a/src/resources/mentor/mentorRouter.js
+++ b/src/resources/mentor/mentorRouter.js
@@ -5,15 +5,15 @@ const { isLoggedIn, isMentor } = require('../../middlewares/auth')
 
 const router = Router()
 
-// /api/item
+// /api/v1/mentor
 router
   .route('/')
   .get(isLoggedIn, controllers.default.getMany)
   .post(isLoggedIn, isMentor, controllers.default.createOne)
 
-// /api/item/:id
+// /api/v1/mentor/id/:id
 router
-  .route('/:id')
+  .route('/id/:id')
   .get(isLoggedIn, controllers.default.getOne)
   .put(isLoggedIn, isMentor, controllers.default.updateOne)
   .delete(isLoggedIn, isMentor, controllers.default.removeOne)
diff --git a/src/resources/news/__tests__/newsFuncTest.js b/src/resources/news/__tests__/newsFuncTest.js
new file mode 100644
index 0000000000000000000000000000000000000000..44b40341989f8b804b124e04e90110ce4f748d2e
--- /dev/null
+++ b/src/resources/news/__tests__/newsFuncTest.js
@@ -0,0 +1,118 @@
+const { app } = require('../../../server')
+const session = require('supertest-session')
+const { merge, has } = require('lodash')
+const { validateKeys } = require('../../../utils/testHelpers')
+
+const { News } = require('../newsModel')
+const endpointUrl = '/api/v1/news'
+const fakeUserJson = {
+  internal_id: 'fakeId',
+  schacc: 'fakeUser',
+  fullName: 'faker Janos',
+  secondaryEmail: 'faker@fake.com',
+}
+let fakeNewsJson = {
+  title: 'A legjobb hír',
+  body: 'A legjobb hír ever man!',
+  creator: 'fakeUSer',
+}
+const defaultKeys = {
+  _id: true,
+  creator: true,
+  title: true,
+  body: true,
+}
+
+describe('/news "Mentor" Functionality', () => {
+  let authSession
+  // Login as mentor
+  beforeEach(async function (done) {
+    let testSession = session(app)
+    testSession.get(`/api/v1/login/mock/mentor`).end(function (err) {
+      if (err) return done(err)
+      authSession = testSession
+      return done()
+    })
+  })
+  //readone
+  test(`GET existing news`, async () => {
+    const newNews = await News.create(fakeNewsJson)
+    let response = await authSession.get(`${endpointUrl}/id/${newNews._id}`)
+    expect(response.statusCode).toBe(200)
+  })
+  test('GET invalid news', async () => {
+    let response = await authSession.get(`${endpointUrl}/id/almafa`)
+    expect(response.statusCode).toBe(422)
+  })
+  // Get Many
+  test(`GET many returns with allowed keys`, async () => {
+    await News.create(fakeNewsJson)
+    await News.create(fakeNewsJson)
+    let response = await authSession.get(endpointUrl)
+    expect(response.statusCode).toBe(200)
+    response.body.data.forEach((eachData) => {
+      validateKeys(eachData, defaultKeys)
+    })
+  })
+  // Create
+  test(`Create news`, async () => {
+    const newNews = await News.create(fakeNewsJson)
+    let response = await authSession.post(`${endpointUrl}/`).send({
+      title: newNews.title,
+      body: newNews.body,
+      creator: newNews.creator,
+    })
+    expect(response.statusCode).toBe(201)
+    validateKeys(response.body.data, defaultKeys)
+  })
+  //Update
+  test(`Update news`, async () => {
+    const newNews = await News.create(fakeNewsJson)
+    let response = await authSession
+      .put(`${endpointUrl}/id/${newNews._id}`)
+      .send({
+        title: 'updatedtitle',
+      })
+    expect(response.statusCode).toBe(200)
+    expect(response.body.data.title).toBe('updatedtitle')
+  })
+  //Delete
+  test(`Delete news`, async () => {
+    const newNews = await News.create(fakeNewsJson)
+    let response = await authSession.delete(`${endpointUrl}/id/${newNews._id}`)
+    expect(response.statusCode).toBe(200)
+  })
+})
+describe('/news "Accepted" Functionality', () => {
+  let authSession
+  // Login as accepted
+  beforeEach(async function (done) {
+    let testSession = session(app)
+    testSession.get(`/api/v1/login/mock/accepted`).end(function (err) {
+      if (err) return done(err)
+      authSession = testSession
+      return done()
+    })
+  })
+  //readone
+  test(`GET existing news`, async () => {
+    const newNews = await News.create(fakeNewsJson)
+    let response = await authSession.get(`${endpointUrl}/id/${newNews._id}`)
+    expect(response.statusCode).toBe(200)
+  })
+  test('GET invalid news', async () => {
+    let response = await authSession.get(`${endpointUrl}/id/almafa`)
+    expect(response.statusCode).toBe(422)
+  })
+  // Get Many
+  test(`GET many returns with allowed keys`, async () => {
+    await News.create(fakeNewsJson)
+    await News.create(fakeNewsJson)
+    let response = await authSession.get(endpointUrl)
+    expect(response.statusCode).toBe(200)
+    response.body.data.forEach((eachData) => {
+      validateKeys(eachData, defaultKeys)
+    })
+  })
+})
+//
diff --git a/src/resources/news/__tests__/newsPermTest.js b/src/resources/news/__tests__/newsPermTest.js
index 2e3735c801d6819a2ac6bb2e211fb226827fc77d..5039915cea8d81c7632f09261941ca390af36637 100644
--- a/src/resources/news/__tests__/newsPermTest.js
+++ b/src/resources/news/__tests__/newsPermTest.js
@@ -12,13 +12,28 @@ const fakeNewsJson = {
 }
 
 describe('/news Permission tests', () => {
+  crudPermTest(
+    app,
+    endpointUrl + '/id',
+    News,
+    'news',
+    fakeNewsJson,
+    [false, false, true, true, true],
+    [
+      // [role, create, readAll, readOne, update, delete]
+      ['none', false, false, false, false, false],
+      ['normal', false, true, true, false, false],
+      ['accepted', false, true, true, false, false],
+      ['mentor', true, true, true, true, true],
+    ]
+  )
   crudPermTest(
     app,
     endpointUrl,
     News,
     'news',
     fakeNewsJson,
-    [true, true, true, true, true],
+    [true, true, false, false, false],
     [
       // [role, create, readAll, readOne, update, delete]
       ['none', false, false, false, false, false],
diff --git a/src/resources/news/newsControllers.js b/src/resources/news/newsControllers.js
index ae07019a722cce094e056563f63d72d7b248c96d..23f6bb8ccd67cf71b4c5f50e2929f4e22fbab8c3 100644
--- a/src/resources/news/newsControllers.js
+++ b/src/resources/news/newsControllers.js
@@ -20,12 +20,11 @@ exports.default.getOne = async (req, res) => {
   } catch (err) {
     if (err.name === 'CastError') {
       // Throwed by Mongoose
-      console.error(err)
       return res.status(422).json({ message: 'Invalid ID provided' })
     }
 
     console.error(err)
-    res.status(400).end()
+    res.status(500).end()
   }
 }
 exports.default.getMany = async (req, res) => {
@@ -43,7 +42,7 @@ exports.default.getMany = async (req, res) => {
     })
   } catch (err) {
     console.error(err)
-    res, status(400).end()
+    res, status(500).end()
   }
 }
 
@@ -66,6 +65,6 @@ exports.default.createOne = async (req, res) => {
     }
 
     console.error(err)
-    return res.status(400).end()
+    return res.status(500).end()
   }
 }
diff --git a/src/resources/news/newsDocs.yml b/src/resources/news/newsDocs.yml
new file mode 100644
index 0000000000000000000000000000000000000000..28f54d3c49468350a8f3b09ade46bac4a5014565
--- /dev/null
+++ b/src/resources/news/newsDocs.yml
@@ -0,0 +1,102 @@
+openapi: '3.0.2'
+info:
+  title: 'News Endpoint'
+  version: '1.0'
+
+paths:
+  /news:
+    get:
+      tags:
+        - 'News'
+      summary: 'Get a List of news'
+      description: 'Have to be logged in.'
+      operationId: 'getAllNews'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: 'array'
+                items:
+                  $ref: '#/components/schemas/News'
+    post:
+      tags:
+        - 'News'
+      summary: 'Create a news'
+      description: 'Have to be mentor for this.'
+      operationId: 'createNews'
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/News'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/News'
+  /news/id/{id}:
+    get:
+      tags:
+        - 'News'
+      summary: 'Get a news by ID'
+      description: 'Have to be logged in for this.'
+      operationId: 'getNews'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/News'
+    put:
+      tags:
+        - 'News'
+      summary: 'Update a news by ID'
+      description: 'Only mentors can update a news.'
+      operationId: 'updateOneNews'
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/News'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/News'
+    delete:
+      tags:
+        - 'News'
+      summary: 'Delete a news by ID'
+      description: 'Only mentors can delete a news.'
+      operationId: 'deleteNews'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/News'
+
+components:
+  schemas:
+    News:
+      type: object
+      properties:
+        title:
+          type: string
+        body:
+          type: string
+        creator:
+          type: string
+          description: schacc of the user
+      required:
+        - title
+        - body
+        - creator
diff --git a/src/resources/news/newsRouter.js b/src/resources/news/newsRouter.js
index c2e6b3d9027cec1d9519a0c014f80ebd17c022c3..47a4c888c2aa6448aa26984a46b1b0da9b14eb18 100644
--- a/src/resources/news/newsRouter.js
+++ b/src/resources/news/newsRouter.js
@@ -5,15 +5,15 @@ const { isLoggedIn, isMentor } = require('../../middlewares/auth')
 
 const router = Router()
 
-// /api/item
+// /api/v1/news
 router
   .route('/')
   .get(isLoggedIn, controllers.default.getMany)
   .post(isLoggedIn, isMentor, controllers.default.createOne)
 
-// /api/item/:id
+// /api/v1/news/id/:id
 router
-  .route('/:id')
+  .route('/id/:id')
   .get(isLoggedIn, controllers.default.getOne)
   .put(isLoggedIn, isMentor, controllers.default.updateOne)
   .delete(isLoggedIn, isMentor, controllers.default.removeOne)
diff --git a/src/resources/settings/__tests__/setingsFuncTest.js b/src/resources/settings/__tests__/setingsFuncTest.js
new file mode 100644
index 0000000000000000000000000000000000000000..c75827e257d74f53df991accf15bb5bd581d6896
--- /dev/null
+++ b/src/resources/settings/__tests__/setingsFuncTest.js
@@ -0,0 +1,41 @@
+const { app } = require('../../../server')
+const session = require('supertest-session')
+
+const { Settings } = require('../settingsModel')
+
+const endpointUrl = '/api/v1/settings'
+
+const fakeSettingsJson = {
+  applicationEndDate: '2020-12-11',
+}
+
+describe('/settings Functionality', () => {
+  let authSession
+  // Login as mentor
+  beforeEach(function (done) {
+    authSession = session(app)
+    authSession.get(`/api/v1/login/mock/mentor`).end(function (err) {
+      if (err) return done(err)
+      return done()
+    })
+  })
+  // Create
+  test(`Create settings`, async () => {
+    let response = await authSession
+      .put(`${endpointUrl}`)
+      .send(fakeSettingsJson)
+    expect(response.statusCode).toBe(201)
+    expect(response.body.data.applicationEndDate).toBe(
+      '2020-12-11T00:00:00.000Z'
+    )
+  })
+  // Get
+  test(`Get settings`, async () => {
+    await Settings.create(fakeSettingsJson)
+    let response = await authSession.get(endpointUrl)
+    expect(response.statusCode).toBe(200)
+    expect(response.body.data.applicationEndDate).toBe(
+      '2020-12-11T00:00:00.000Z'
+    )
+  })
+})
diff --git a/src/resources/settings/__tests__/settingsPermTest.js b/src/resources/settings/__tests__/settingsPermTest.js
new file mode 100644
index 0000000000000000000000000000000000000000..f0a32c26e2c5ba3e19b8521307e30f76b981b4e0
--- /dev/null
+++ b/src/resources/settings/__tests__/settingsPermTest.js
@@ -0,0 +1,29 @@
+const { app } = require('../../../server')
+const { crudPermTest } = require('../../../utils/testHelpers')
+
+const { Settings } = require('../settingsModel')
+
+const endpointUrl = '/api/v1/settings'
+
+const fakeSettingsJson = {
+  applicationEndDate: '2020-12-11',
+}
+
+// put isn't tested, but should be okay
+describe('/settings Permission tests', () => {
+  crudPermTest(
+    app,
+    endpointUrl,
+    Settings,
+    'settings',
+    fakeSettingsJson,
+    [false, true, false, false, false],
+    [
+      // [role, create, readAll, readOne, update, delete]
+      ['none', false, true, false, false, false],
+      ['normal', false, true, false, false, false],
+      ['accepted', false, true, false, false, false],
+      ['mentor', false, true, false, true, false],
+    ]
+  )
+})
diff --git a/src/resources/settings/settingsControllers.js b/src/resources/settings/settingsControllers.js
index 9ddba2ef7a711fe7198829f4df9d0124daa1c52e..54123924b5c8faa6e743e84dc78789c10d9f74c4 100644
--- a/src/resources/settings/settingsControllers.js
+++ b/src/resources/settings/settingsControllers.js
@@ -2,42 +2,34 @@ const { crudControllers } = require('../../utils/crud')
 const { Settings } = require('./settingsModel')
 const { pick } = require('lodash')
 
-exports.default = crudControllers(Settings, ['applicationEndDate'])
+module.exports = crudControllers(Settings, ['applicationEndDate'])
 
-// Make sure that only one setting exists
-exports.default.createOne = async (req, res) => {
+module.exports.getOne = async (req, res) => {
   try {
-    if (await Settings.findOne().lean().exec())
-      throw {
-        name: 'alreadyExists',
-        message: `Already exists a setting, update it!`,
-      }
+    const doc = await Settings.findOne().lean().exec()
 
-    const doc = await Settings.create({ ...req.body })
-    return res.status(201).json({ data: pick(doc, ['applicationEndDate']) })
+    if (!doc) {
+      return res.status(404).end()
+    }
+    res.status(200).json({ data: pick(doc, ['applicationEndDate']) })
   } catch (err) {
-    if (err.name == 'ValidationError') {
-      // Mongoose validation errors
-      let messages = []
-      for (field in err.errors) {
-        messages.push(err.errors[field].message)
-      }
-      return res.status(422).json({ messages })
+    if (err.name == 'CastError') {
+      return res.status(422).json('Invalid ID provided')
+    } else {
+      console.error(err)
+      res.status(400).end()
     }
-    if (err.name == 'alreadyExists')
-      return res.status(409).json({ messages: err.message })
-    console.error(err)
-    return res.status(400).end()
   }
 }
 
-exports.default.updateOne = async (req, res) => {
+// If there is no settings, then create it
+module.exports.updateOne = async (req, res) => {
   try {
     const oldSettings = await Settings.findOne().lean().exec()
-    if (!oldSettings)
-      return res
-        .status(404)
-        .json({ messages: 'There is no settings to update' })
+    if (!oldSettings) {
+      const doc = await Settings.create({ ...req.body })
+      return res.status(201).json({ data: pick(doc, ['applicationEndDate']) })
+    }
     const updatedSettings = await Settings.findOneAndUpdate(
       {
         _id: oldSettings._id,
diff --git a/src/resources/settings/settingsDocs.yml b/src/resources/settings/settingsDocs.yml
new file mode 100644
index 0000000000000000000000000000000000000000..91af7bff02c244ff8a3e688b88b87171dfdf7cce
--- /dev/null
+++ b/src/resources/settings/settingsDocs.yml
@@ -0,0 +1,51 @@
+openapi: '3.0.2'
+info:
+  title: 'Settings Endpoint'
+  version: '1.0'
+
+paths:
+  /settings:
+    get:
+      tags:
+        - 'Settings'
+      summary: 'Get the global settings'
+      description: 'Can be get by all user. Contains the global settings.'
+      operationId: 'getSettings'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: 'array'
+                items:
+                  $ref: '#/components/schemas/Settings'
+    put:
+      tags:
+        - 'Settings'
+      summary: 'Update or create if doesnt exist the global settings'
+      description: 'Have to be mentor.'
+      operationId: 'updateSettings'
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Settings'
+      responses:
+        '201':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Settings'
+
+components:
+  schemas:
+    Settings:
+      type: object
+      properties:
+        applicationEndDate:
+          type: string
+          format: date-time
+      required:
+        - applicationEndDate
diff --git a/src/resources/settings/settingsRouter.js b/src/resources/settings/settingsRouter.js
index ba1cdd985465a37f585442c3af1913a59786aca2..0daa1d32501c22bd0f45a01a2b483cd3fe14a75a 100644
--- a/src/resources/settings/settingsRouter.js
+++ b/src/resources/settings/settingsRouter.js
@@ -8,15 +8,7 @@ const router = Router()
 // /api/settings
 router
   .route('/')
-  .get(isLoggedIn, isMentor, controllers.default.getMany)
-  .post(isLoggedIn, isMentor, controllers.default.createOne)
-  .put(isLoggedIn, isMentor, controllers.default.updateOne)
-
-// /api/settings/:id
-router
-  .route('/:id')
-  .get(isLoggedIn, isMentor, controllers.default.getOne)
-  .put(isLoggedIn, isMentor, controllers.default.updateOne)
-  .delete(isLoggedIn, isMentor, controllers.default.removeOne)
+  .get(controllers.getOne)
+  .put(isLoggedIn, isMentor, controllers.updateOne)
 
 exports.default = router
diff --git a/src/resources/solution/solutionControllers.js b/src/resources/solution/solutionControllers.js
index 524b0ebe157656e73a17df5322b43b8591d66058..50316b9373e5fb7456a94689670cf40b532b6a9d 100644
--- a/src/resources/solution/solutionControllers.js
+++ b/src/resources/solution/solutionControllers.js
@@ -1,4 +1,188 @@
 const { crudControllers } = require('../../utils/crud')
 const { Solution } = require('./solutionModel')
+const { Task } = require('../task/taskModel')
+const { pick } = require('lodash')
 
 exports.default = crudControllers(Solution)
+
+exports.default.createOne = async (req, res) => {
+  try {
+    const task = await Task.findById(req.body.task)
+    let solution
+    if (req.user.role === 'mentor' && req.body.creator) {
+      // Mentor Creates/Updates a Solution to someone
+      solution = await Solution.findOneAndUpdate(
+        { creator: req.body.creator, task: req.body.task },
+        { ...req.body },
+        {
+          upsert: true, // Create new One if there is no match
+          returnOriginal: false,
+          setDefaultsOnInsert: true,
+          runValidators: true,
+        }
+      )
+        .lean()
+        .exec()
+    } else {
+      // Someone creates a solution
+      if (req.user.role != 'mentor') {
+        delete req.body.isAccepted
+        delete req.body.comments
+      }
+      if (task.deadline < new Date())
+        return res.status(400).json({
+          message: `Can't create new Solution! End date was ${task.deadline.toDateString()}`,
+        })
+
+      solution = await Solution.findOneAndUpdate(
+        { creator: req.user.schacc, task: req.body.task },
+        { ...req.body },
+        {
+          upsert: true, // Create new One if there is no match
+          returnOriginal: false,
+          setDefaultsOnInsert: true,
+          runValidators: true,
+        }
+      )
+        .lean()
+        .exec()
+    }
+    if (task.solutions.indexOf(solution._id) == -1) {
+      task.solutions.push(solution._id)
+      await task.save()
+    }
+
+    let retSolution = await Solution.findById({ _id: solution._id })
+      .populate('_creator', '-_id fullName nickName schacc')
+      .populate('comments', 'text creator createdAt')
+      .lean()
+      .exec()
+
+    retSolution.creator = retSolution._creator
+    return res.status(200).json({
+      data: pick(retSolution, [
+        '_id',
+        'creator',
+        'title',
+        'description',
+        'file',
+        'task',
+        'comments',
+        'createdAt',
+        'updatedAt',
+        'isAccepted',
+      ]),
+    })
+  } catch (err) {
+    if (err.name == 'ValidationError') {
+      // Throwed by Mongoose
+      let messages = []
+      for (field in err.errors) {
+        messages.push(err.errors[field].message)
+      }
+      return res.status(422).json({ messages })
+    }
+    console.error(err)
+    return res.status(500).json({ message: err.message })
+  }
+}
+
+exports.default.getMany = async (req, res) => {
+  try {
+    let solutions = undefined
+
+    if (req.user.role === 'mentor')
+      solutions = await Solution.find()
+        .populate('_creator', '-_id fullName nickName schacc')
+        .populate('comments', 'text creator createdAt')
+        .select('-__v')
+        .lean()
+        .exec()
+    else
+      solutions = await Solution.find({ user: req.user._id })
+        .populate('_creator', '-_id fullName nickName')
+        .populate('comments', '-_id text creator createdAt')
+        .select('-__v')
+        .lean()
+        .exec()
+
+    return res.status(200).json({
+      data: solutions.map((e) => {
+        e.creator = e._creator
+        return pick(e, [
+          '_id',
+          'creator',
+          'title',
+          'description',
+          'file',
+          'task',
+          'comments',
+          'createdAt',
+          'updatedAt',
+          'isAccepted',
+        ])
+      }),
+    })
+  } catch (err) {
+    if (err.name == 'ValidationError') {
+      // Throwed by Mongoose
+      let messages = []
+      for (field in err.errors) {
+        messages.push(err.errors[field].message)
+      }
+      return res.status(422).json({ messages })
+    }
+    console.error(err)
+    return res.status(500).json({ message: err.message })
+  }
+}
+
+exports.default.getOne = async (req, res) => {
+  try {
+    let solution = await Solution.findById({ _id: req.params.id })
+      .populate('_creator', '-_id fullName nickName')
+      .populate('comments', 'text creator createdAt')
+      .select('-__v')
+      .lean()
+      .exec()
+
+    if (!solution)
+      return res.status(404).json({ messages: ['No such solution.'] })
+
+    if (req.user.schacc !== solution.creator && req.user.role !== 'mentor') {
+      return res
+        .status(403)
+        .json({ message: `You don't have permission for this solution.` })
+    }
+
+    return res.status(200).json({
+      data: pick(solution, [
+        '_id',
+        'creator',
+        'title',
+        'description',
+        'file',
+        'task',
+        'comments',
+        'createdAt',
+        'updatedAt',
+        'isAccepted',
+      ]),
+    })
+  } catch (err) {
+    if (err.name == 'ValidationError') {
+      // Throwed by Mongoose
+      let messages = []
+      for (field in err.errors) {
+        messages.push(err.errors[field].message)
+      }
+      return res.status(422).json({ messages })
+    }
+    console.error(err)
+    return res.status(500).json({ message: err.message })
+  }
+}
+
+exports.default.notSupported = async (req, res) => {
+  res.status(404).json({ data: { message: 'Not supported operation!' } })
+}
diff --git a/src/resources/solution/solutionDocs.yml b/src/resources/solution/solutionDocs.yml
new file mode 100644
index 0000000000000000000000000000000000000000..00b37c67515588bb6c3917adf627cd9ac5ffc5fa
--- /dev/null
+++ b/src/resources/solution/solutionDocs.yml
@@ -0,0 +1,124 @@
+openapi: '3.0.2'
+info:
+  title: 'Solution Endpoint'
+  version: '1.0'
+
+paths:
+  /solution:
+    get:
+      tags:
+        - 'Solution'
+      summary: 'Get a List of solution'
+      description: 'Have to be accepted or mentor. 
+        As an accepted only own solutions can be seen.'
+      operationId: 'getAllSolution'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: 'array'
+                items:
+                  $ref: '#/components/schemas/Solution'
+    post:
+      tags:
+        - 'Solution'
+      summary: 'Create a solution'
+      description: 'Have to be accepted or mentor. 
+        As an accepted only own own solution can be made.'
+      operationId: 'createSolution'
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Solution'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Solution'
+  /solution/id/{id}:
+    get:
+      tags:
+        - 'Solution'
+      summary: 'Get a solution by ID'
+      description: 'Have to be accepted or mentor. 
+        As an accepted only own solutions can be get.'
+      operationId: 'getSolution'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Solution'
+    put:
+      tags:
+        - 'Solution'
+      summary: 'Update a solution by ID'
+      description: 'Have to be accepted or mentor. 
+        As an accepted only own solutions can be get. 
+        After deadline cant make new solution as accepted.'
+      operationId: 'updateOneSolution'
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Solution'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Solution'
+    delete:
+      tags:
+        - 'Solution'
+      summary: 'Delete a solution by ID'
+      description: 'Have to be accepted or mentor. 
+      As an accepted only own solutions can be delted. 
+      After deadline cant make new solution as accepted.'
+      operationId: 'deleteSolution'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Solution'
+
+components:
+  schemas:
+    Solution:
+      type: object
+      properties:
+        task:
+          type: string
+          description: cuid of the task
+        title:
+          type: string
+        description:
+          type: string
+        file:
+          type: string
+        creator:
+          type: string
+          description: schacc of the user
+        comments:
+          type: array
+          items:
+            type: string
+            description: cuid of each comment
+        isAccepted:
+          type: boolean
+          default: false
+      required:
+        - task
+        - title
+        - description
+        - creator
+        - isAccepted
diff --git a/src/resources/solution/solutionModel.js b/src/resources/solution/solutionModel.js
index cc973a356d3aa438e5070efe4ffd8aafe4b181c5..11c1a52a47585bca4a70535428b389661343757c 100644
--- a/src/resources/solution/solutionModel.js
+++ b/src/resources/solution/solutionModel.js
@@ -2,6 +2,11 @@ const mongoose = require('mongoose')
 
 const SolutionSchema = new mongoose.Schema(
   {
+    task: {
+      type: mongoose.Schema.Types.ObjectId,
+      ref: 'task',
+      required: true,
+    },
     title: {
       type: String,
       required: true,
@@ -12,30 +17,32 @@ const SolutionSchema = new mongoose.Schema(
     },
     file: {
       type: String,
-      required: true,
     },
-    user: {
-      type: mongoose.Schema.Types.ObjectId,
-      ref: 'user',
+    creator: {
+      type: String,
       required: true,
     },
-    comment: [
+    comments: [
       {
         type: mongoose.Schema.Types.ObjectId,
         ref: 'comment',
-        required: true,
       },
     ],
     isAccepted: {
       type: Boolean,
       required: true,
+      default: false,
     },
   },
   { timestamps: true }
 )
 
-// Careful with the docs, there are some deprecated ones
-// https://mongoosejs.com/docs/guide.html
+SolutionSchema.virtual('_creator', {
+  ref: 'user',
+  localField: 'creator',
+  foreignField: 'schacc',
+  justOne: true,
+})
 
 const Solution = mongoose.model('solution', SolutionSchema)
 
diff --git a/src/resources/solution/solutionRouter.js b/src/resources/solution/solutionRouter.js
index f123b0dd11e2ebeecdc6e434d2db4395cbca999c..ec248934ba3847ecb204c0117f0e259d407a8e37 100644
--- a/src/resources/solution/solutionRouter.js
+++ b/src/resources/solution/solutionRouter.js
@@ -1,19 +1,20 @@
 const { Router } = require('express')
 const controllers = require('./solutionControllers')
+const { isLoggedIn, isAcceptedOrMentor } = require('../../middlewares/auth')
 
 const router = Router()
 
-// /api/item
+// /api/v1/solution
 router
   .route('/')
-  .get(controllers.default.getMany)
-  .post(controllers.default.createOne)
+  .get(isLoggedIn, isAcceptedOrMentor, controllers.default.getMany)
+  .post(isLoggedIn, isAcceptedOrMentor, controllers.default.createOne)
 
-// /api/item/:id
+// /api/v1/solution/id/:id
 router
-  .route('/:id')
-  .get(controllers.default.getOne)
-  .put(controllers.default.updateOne)
-  .delete(controllers.default.removeOne)
+  .route('/id/:id')
+  .get(isLoggedIn, isAcceptedOrMentor, controllers.default.getOne)
+  .put(isLoggedIn, isAcceptedOrMentor, controllers.default.notSupported)
+  .delete(isLoggedIn, isAcceptedOrMentor, controllers.default.notSupported)
 
 exports.default = router
diff --git a/src/resources/task/__tests__/taskFuncTest.js b/src/resources/task/__tests__/taskFuncTest.js
new file mode 100644
index 0000000000000000000000000000000000000000..8acc47f99c308b79470bdf5953ca2a4085d2cf63
--- /dev/null
+++ b/src/resources/task/__tests__/taskFuncTest.js
@@ -0,0 +1,125 @@
+const { app } = require('../../../server')
+const session = require('supertest-session')
+const { merge, has } = require('lodash')
+const { validateKeys } = require('../../../utils/testHelpers')
+
+const { User } = require('../../user/userModel')
+const { Task } = require('../taskModel')
+
+const endpointUrl = '/api/v1/task'
+const fakeUserJson = {
+  internal_id: 'fakeId',
+  schacc: 'fakeUser',
+  fullName: 'faker Janos',
+  secondaryEmail: 'faker@fake.com',
+}
+let fakeTaskJson = {
+  title: 'The greatest task',
+  description: 'Ezt kell csinálni a greatest tasknál',
+  deadline: '2020.12.31',
+  bit: '10',
+}
+const defaultKeys = {
+  _id: true,
+  title: true,
+  description: true,
+  deadline: true,
+  bit: true,
+}
+
+describe('/task "Mentor" Functionality', () => {
+  let authSession
+  // Login as mentor
+  beforeEach(async function (done) {
+    let testSession = session(app)
+    testSession.get(`/api/v1/login/mock/mentor`).end(function (err) {
+      if (err) return done(err)
+      authSession = testSession
+      return done()
+    })
+  })
+  //readone
+  test(`GET existing task`, async () => {
+    const newTask = await Task.create(fakeTaskJson)
+    let response = await authSession.get(`${endpointUrl}/id/${newTask._id}`)
+    expect(response.statusCode).toBe(200)
+  })
+  test('GET invalid task', async () => {
+    let response = await authSession.get(`${endpointUrl}/id/almafa`)
+    expect(response.statusCode).toBe(422)
+  })
+  // Get Many
+  test(`GET many returns with allowed keys`, async () => {
+    await Task.create(fakeTaskJson)
+    await Task.create(fakeTaskJson)
+    let response = await authSession.get(endpointUrl)
+    expect(response.statusCode).toBe(200)
+    response.body.data.forEach((eachData) => {
+      validateKeys(eachData, defaultKeys)
+    })
+  })
+  // Create
+  test(`Create task`, async () => {
+    const newTask = await Task.create(fakeTaskJson)
+    let response = await authSession.post(`${endpointUrl}/`).send({
+      title: newTask.title,
+      description: newTask.description,
+      deadline: newTask.deadline,
+      createData: newTask.createData,
+      bit: newTask.bit,
+    })
+    expect(response.statusCode).toBe(201)
+    validateKeys(response.body.data, defaultKeys)
+  })
+  //Update
+  test(`Update task`, async () => {
+    const newTask = await Task.create(fakeTaskJson)
+    let response = await authSession
+      .put(`${endpointUrl}/id/${newTask._id}`)
+      .send({
+        title: 'updatedtitle',
+      })
+    expect(response.statusCode).toBe(200)
+    expect(response.body.data.title).toBe('updatedtitle')
+  })
+  //Delete
+  test(`Delete task`, async () => {
+    const newTask = await Task.create(fakeTaskJson)
+    let response = await authSession.delete(`${endpointUrl}/id/${newTask._id}`)
+    expect(response.statusCode).toBe(200)
+  })
+})
+//Nem számít az ,hogy melyikkel teszteled mert mind2nak ugyan olyannak kell lennie.
+//normal=accepted
+describe('/task "Accepted" Functionality', () => {
+  let authSession
+  // Login as accepted and create a group
+  beforeEach(async function (done) {
+    let testSession = session(app)
+    testSession.get(`/api/v1/login/mock/accepted`).end(function (err) {
+      if (err) return done(err)
+      authSession = testSession
+      return done()
+    })
+  })
+  //readone
+  test(`GET existing task`, async () => {
+    const newTask = await Task.create(fakeTaskJson)
+    let response = await authSession.get(`${endpointUrl}/id/${newTask._id}`)
+    expect(response.statusCode).toBe(200)
+  })
+  test('GET invalid task', async () => {
+    let response = await authSession.get(`${endpointUrl}/id/almafa`)
+    expect(response.statusCode).toBe(422)
+  })
+  // Get Many
+  test(`GET many returns with allowed keys`, async () => {
+    await Task.create(fakeTaskJson)
+    await Task.create(fakeTaskJson)
+    let response = await authSession.get(endpointUrl)
+    expect(response.statusCode).toBe(200)
+    response.body.data.forEach((eachData) => {
+      validateKeys(eachData, defaultKeys)
+    })
+  })
+})
diff --git a/src/resources/task/__tests__/taskPermTest.js b/src/resources/task/__tests__/taskPermTest.js
index 478ba9b19bdba5a6d44c8839a4f867485fdfc2a7..9d68f713b9962d3148c980350e4822dbe3871a86 100644
--- a/src/resources/task/__tests__/taskPermTest.js
+++ b/src/resources/task/__tests__/taskPermTest.js
@@ -15,13 +15,28 @@ const fakeTaskJson = {
 }
 
 describe('/task Permission tests', () => {
+  crudPermTest(
+    app,
+    endpointUrl + '/id',
+    Task,
+    'task',
+    fakeTaskJson,
+    [false, false, true, true, true],
+    [
+      // [role, create, readAll, readOne, update, delete]
+      ['none', false, false, false, false, false],
+      ['normal', false, false, false, false, false],
+      ['accepted', false, true, true, false, false],
+      ['mentor', true, true, true, true, true],
+    ]
+  )
   crudPermTest(
     app,
     endpointUrl,
     Task,
     'task',
     fakeTaskJson,
-    [true, true, true, true, true],
+    [true, true, false, false, false],
     [
       // [role, create, readAll, readOne, update, delete]
       ['none', false, false, false, false, false],
diff --git a/src/resources/task/taskControllers.js b/src/resources/task/taskControllers.js
index 129937434f8712460cd87c931eda5eb92373d386..865d652a5dbd5874a387cb13af24abdae65b2028 100644
--- a/src/resources/task/taskControllers.js
+++ b/src/resources/task/taskControllers.js
@@ -7,7 +7,6 @@ exports.default = crudControllers(Task, [
   'title',
   'description',
   'deadline',
-  'createData',
   'bit',
   'creator',
 ])
@@ -18,6 +17,7 @@ exports.default.getOne = async (req, res) => {
         path: '_creator',
         select: '-_id schacc fullName secondaryEmail',
       })
+      .populate('comments', 'text creator createdAt')
       .lean()
       .exec()
 
@@ -32,6 +32,7 @@ exports.default.getOne = async (req, res) => {
           'createData',
           'bit',
           'creator',
+          'solutions',
         ]),
       })
     } else {
@@ -40,12 +41,11 @@ exports.default.getOne = async (req, res) => {
   } catch (err) {
     if (err.name === 'CastError') {
       // Throwed by Mongoose
-      console.error(err)
       return res.status(422).json({ message: 'Invalid ID provided' })
     }
 
     console.error(err)
-    res.status(400).end()
+    res.status(500).end()
   }
 }
 exports.default.getMany = async (req, res) => {
@@ -55,6 +55,7 @@ exports.default.getMany = async (req, res) => {
         path: '_creator',
         select: '-_id schacc fullName secondaryEmail',
       })
+      .populate('comments', 'text creator createdAt')
       .lean()
       .exec()
 
@@ -69,12 +70,13 @@ exports.default.getMany = async (req, res) => {
           'createData',
           'bit',
           'creator',
+          'solutions',
         ])
       }),
     })
   } catch (err) {
     console.error(err)
-    res, status(400).end()
+    res.status(500).end()
   }
 }
 exports.default.createOne = async (req, res) => {
@@ -87,6 +89,7 @@ exports.default.createOne = async (req, res) => {
         'createData',
         'bit',
         'creator',
+        'solutions',
       ])
     )
     res.status(201).json({
@@ -98,6 +101,7 @@ exports.default.createOne = async (req, res) => {
         'createData',
         'bit',
         'creator',
+        'solutions',
       ]),
     })
   } catch (err) {
@@ -111,6 +115,6 @@ exports.default.createOne = async (req, res) => {
     }
 
     console.error(err)
-    return res.status(400).end()
+    return res.status(500).end()
   }
 }
diff --git a/src/resources/task/taskDocs.yml b/src/resources/task/taskDocs.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3e73925a92a9966484bb743daab956207fd80eb1
--- /dev/null
+++ b/src/resources/task/taskDocs.yml
@@ -0,0 +1,119 @@
+openapi: '3.0.2'
+info:
+  title: 'Task Endpoint'
+  version: '1.0'
+
+paths:
+  /task:
+    get:
+      tags:
+        - 'Task'
+      summary: 'Get a List of tasks'
+      description: 'Have to be accepted or mentor.'
+      operationId: 'getAllTask'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: 'array'
+                items:
+                  $ref: '#/components/schemas/Task'
+    post:
+      tags:
+        - 'Task'
+      summary: 'Create a task'
+      description: 'Have to be mentor.'
+      operationId: 'createTask'
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Task'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Task'
+  /task/id/{id}:
+    get:
+      tags:
+        - 'Task'
+      summary: 'Get a task by ID'
+      description: 'Have to be accepted or mentor.'
+      operationId: 'getTask'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Task'
+    put:
+      tags:
+        - 'Task'
+      summary: 'Update a task by ID'
+      description: 'Have to be mentor.'
+      operationId: 'updateOneTask'
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Task'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Task'
+    delete:
+      tags:
+        - 'Task'
+      summary: 'Delete a task by ID'
+      description: 'Have to be mentor.'
+      operationId: 'deleteTask'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Task'
+
+components:
+  schemas:
+    Task:
+      type: object
+      properties:
+        title:
+          type: string
+        description:
+          type: string
+        deadline:
+          type: string
+          format: date-time
+        bit:
+          type: number
+          default: 0
+        creator:
+          type: string
+          description: schacc of the user. Default is the current user.
+        tasks:
+          type: array
+          items:
+            type: string
+            description: cuid of each task
+        comments:
+          type: array
+          items:
+            type: string
+            description: cuid of each comment
+      required:
+        - title
+        - description
+        - deadline
+        - bit
diff --git a/src/resources/task/taskModel.js b/src/resources/task/taskModel.js
index 1832ca9012baa87b6c0f31eaa607aa641d89f7b2..14a4660be390283a14eb53d4ae2094dc0ef10bd7 100644
--- a/src/resources/task/taskModel.js
+++ b/src/resources/task/taskModel.js
@@ -14,17 +14,26 @@ const TaskSchema = new mongoose.Schema(
       type: Date,
       required: true,
     },
-    createData: {
-      type: String,
-      required: false,
-    },
     bit: {
       type: Number,
-      require: true,
+      required: true,
+      default: 0,
     },
     creator: {
       type: String,
     },
+    solutions: [
+      {
+        type: mongoose.Schema.Types.ObjectId,
+        ref: 'solution',
+      },
+    ],
+    comments: [
+      {
+        type: mongoose.Schema.Types.ObjectId,
+        ref: 'comment',
+      },
+    ],
   },
   { timestamps: true }
 )
diff --git a/src/resources/task/taskRouter.js b/src/resources/task/taskRouter.js
index de80cac6bd5570d3a1a27e4bba99c884b76c2319..ecd9fbb1f48c1889fe878d627e0b8a4e7c69a2b4 100644
--- a/src/resources/task/taskRouter.js
+++ b/src/resources/task/taskRouter.js
@@ -9,15 +9,15 @@ const {
 
 const router = Router()
 
-// /api/item
+// /api/v1/task
 router
   .route('/')
   .get(isLoggedIn, isAcceptedOrMentor, controllers.default.getMany)
   .post(isLoggedIn, isMentor, controllers.default.createOne)
 
-// /api/item/:id
+// /api/v1/task/id/:id
 router
-  .route('/:id')
+  .route('/id/:id')
   .get(isLoggedIn, isAcceptedOrMentor, controllers.default.getOne)
   .put(isLoggedIn, isMentor, controllers.default.updateOne)
   .delete(isLoggedIn, isMentor, controllers.default.removeOne)
diff --git a/src/resources/user/__tests__/userFuncTest.js b/src/resources/user/__tests__/userFuncTest.js
index 78bc44144537bbd8a27cd36bcf50d20f66d4f86f..973d7671562048b880459fecb73d62e4fe4f854d 100644
--- a/src/resources/user/__tests__/userFuncTest.js
+++ b/src/resources/user/__tests__/userFuncTest.js
@@ -42,7 +42,9 @@ describe('/user "Mentor" Functionality', () => {
   // GET One
   test(`GET one returns with allowed keys`, async () => {
     let newUser = await User.create(fakeUserJson)
-    let response = await authSession.get(`${endpointUrl}/${newUser.schacc}`)
+    let response = await authSession.get(
+      `${endpointUrl}/schacc/${newUser.schacc}`
+    )
     expect(response.statusCode).toBe(200)
 
     validateKeys(
@@ -52,11 +54,11 @@ describe('/user "Mentor" Functionality', () => {
     newUser = await User.create(
       Object.assign({}, fakeUserJson, { imagePath: 'almafa', schacc: 'apple' })
     )
-    response = await authSession.get(`${endpointUrl}/${newUser.schacc}`)
+    response = await authSession.get(`${endpointUrl}/schacc/${newUser.schacc}`)
     expect(has(response.body.data, 'imagePath')).toBe(true)
   })
   test(`GET own user returns with allowed keys`, async () => {
-    const response = await authSession.get(`/api/v1/extra/me`)
+    const response = await authSession.get(`${endpointUrl}/me`)
 
     expect(response.statusCode).toBe(200)
     validateKeys(
@@ -79,7 +81,9 @@ describe('/user "Mentor" Functionality', () => {
   // SoftDelete
   test(`Delete user returns with allowed keys`, async () => {
     const newUser = await User.create(fakeUserJson)
-    let response = await authSession.delete(`${endpointUrl}/${newUser.schacc}`)
+    let response = await authSession.delete(
+      `${endpointUrl}/schacc/${newUser.schacc}`
+    )
     expect(response.statusCode).toBe(200)
     validateKeys(
       response.body.data,
@@ -92,7 +96,7 @@ describe('/user "Mentor" Functionality', () => {
   test(`Update user returns with allowed keys`, async () => {
     const newUser = await User.create(fakeUserJson)
     let response = await authSession
-      .put(`${endpointUrl}/${newUser.schacc}`)
+      .put(`${endpointUrl}/schacc/${newUser.schacc}`)
       .send({
         fullName: 'Janos',
         secondaryEmail: 'jani@gmail.com',
@@ -119,13 +123,22 @@ describe('/user "Mentor" Functionality', () => {
   test(`Update with invalid email`, async () => {
     const newUser = await User.create(fakeUserJson)
     let response = await authSession
-      .put(`${endpointUrl}/${newUser.schacc}`)
+      .put(`${endpointUrl}/schacc/${newUser.schacc}`)
       .send({
         secondaryEmail: 'testemail',
       })
     expect(response.statusCode).toBe(422)
     expect(response.body.messages).not.toBe(undefined)
   })
+  test(`GET users by role`, async () => {
+    const user = await User.create(fakeUserJson)
+    let response = await authSession.get(`${endpointUrl}/role/normal`)
+    expect(response.body.data.length).toBe(1)
+    response = await authSession.get(`${endpointUrl}/role/accepted`)
+    expect(response.body.data.length).toBe(0)
+    response = await authSession.get(`${endpointUrl}/role/mentor`)
+    expect(response.body.data.length).toBe(1)
+  })
 })
 
 describe('/user "Accepted" Functionality', () => {
@@ -140,13 +153,13 @@ describe('/user "Accepted" Functionality', () => {
   })
   // GET One
   test(`GET own user returns with allowed keys`, async () => {
-    const response = await authSession.get(`/api/v1/extra/me`)
+    const response = await authSession.get(`${endpointUrl}/me`)
     expect(response.statusCode).toBe(200)
     validateKeys(response.body.data, defaultKeys)
   })
   // Update own user
   test(`Update own user returns with allowed keys`, async () => {
-    let response = await authSession.put(`/api/v1/extra/me`).send({
+    let response = await authSession.put(`${endpointUrl}/me`).send({
       fullName: 'Janos',
       secondaryEmail: 'jani@gmail.com',
       bit: 10,
@@ -185,13 +198,13 @@ describe('/user "Normal" Functionality', () => {
   })
   // GET One
   test(`GET own user returns with allowed keys`, async () => {
-    const response = await authSession.get(`/api/v1/extra/me`)
+    const response = await authSession.get(`${endpointUrl}/me`)
     expect(response.statusCode).toBe(200)
     validateKeys(response.body.data, defaultKeys)
   })
   // Update own user
   test(`Update own user returns with allowed keys`, async () => {
-    let response = await authSession.put(`/api/v1/extra/me`).send({
+    let response = await authSession.put(`${endpointUrl}/me`).send({
       fullName: 'Janos',
       secondaryEmail: 'jani@gmail.com',
       bit: 10,
diff --git a/src/resources/user/__tests__/userPermTest.js b/src/resources/user/__tests__/userPermTest.js
index f51708520ff91a3259f36f4c2fcbf705bbe9d239..0536d29a945eceda0af91e6ad9cbe05b0602d3fd 100644
--- a/src/resources/user/__tests__/userPermTest.js
+++ b/src/resources/user/__tests__/userPermTest.js
@@ -17,11 +17,11 @@ describe('/user Permission tests', () => {
   let authSession
   crudPermTest(
     app,
-    endpointUrl,
+    endpointUrl + '/schacc',
     User,
     'user',
     fakeUserJson,
-    [false, true, true, true, true],
+    [false, false, true, true, true],
     [
       // [role, create, readAll, readOne, update, delete]
       ['none', false, false, false, false, false],
@@ -41,14 +41,33 @@ describe('/user Permission tests', () => {
       })
     })
     // All roles
-    test(`Can Get own user on /:id or on /me`, async () => {
+    test(`Can Get own user on own /schacc/{schacc} or on /me`, async () => {
       user = await User.findOne().lean().exec()
-      let response = await authSession.get(`${endpointUrl}/${user.schacc}`)
+      let response = await authSession.get(
+        `${endpointUrl}/schacc/${user.schacc}`
+      )
       expect(response.statusCode).toBe(200)
       expect(response.body.data.schacc).toBe(user.schacc)
-      response = await authSession.get(`/api/v1/extra/me`)
+      response = await authSession.get(`${endpointUrl}/me`)
       expect(response.statusCode).toBe(200)
       expect(response.body.data.schacc).toBe(user.schacc)
     })
   })
+
+  crudPermTest(
+    app,
+    endpointUrl,
+    User,
+    'user',
+    fakeUserJson,
+    [false, true, false, false, false],
+    [
+      // [role, create, readAll, readOne, update, delete]
+      ['none', false, false, false, false, false],
+      ['normal', false, false, false, false, false],
+      ['accepted', false, false, false, false, false],
+      ['mentor', false, true, true, true, true],
+    ],
+    { schacc: 'alma' }
+  )
 })
diff --git a/src/resources/user/userControllers.js b/src/resources/user/userControllers.js
index 8543e6a9db1f7d1bce99d48cf111a2706fbf9994..875314b1a99dd76d79143b6950b1e87324ca017b 100644
--- a/src/resources/user/userControllers.js
+++ b/src/resources/user/userControllers.js
@@ -2,7 +2,7 @@ const { crudControllers, getMany } = require('../../utils/crud')
 const { User } = require('./userModel')
 const { pick } = require('lodash')
 
-const defaultKeys = [
+const pickedKeys = [
   'schacc',
   'fullName',
   'secondaryEmail',
@@ -29,18 +29,16 @@ const getUpdateKeysByRole = (role) => {
   return notMentorKeys
 }
 
-exports.default = crudControllers(User, defaultKeys)
-
-exports.default.getOne = async (req, res) => {
+module.exports.getOne = async (req, res) => {
   try {
     // Get Own User
-    if (req.params.id === req.user.schacc && req.user.role !== 'mentor')
-      return res.status(200).json({ data: pick(req.user, defaultKeys) })
+    if (req.params.schacc === req.user.schacc && req.user.role !== 'mentor')
+      return res.status(200).json({ data: pick(req.user, pickedKeys) })
 
     // Get Other User
     if (req.user.role !== 'mentor') return res.status(403).end()
 
-    const userSchacc = req.params.id
+    const userSchacc = req.params.schacc
 
     // Get user from db
     const user = await User.findOne({ schacc: userSchacc }).lean().exec()
@@ -49,7 +47,7 @@ exports.default.getOne = async (req, res) => {
 
     return res
       .status(200)
-      .json({ data: pick(user, [...defaultKeys, 'bit', 'presence']) })
+      .json({ data: pick(user, [...pickedKeys, 'bit', 'presence']) })
   } catch (err) {
     if (err.name === 'CastError')
       // Throwed by Mongoose
@@ -61,13 +59,24 @@ exports.default.getOne = async (req, res) => {
 }
 
 // Overwrite the returned keys
-exports.default.getMany = getMany(User, [...defaultKeys, 'bit', 'presence'])
+module.exports.getMany = getMany(User, [...pickedKeys, 'bit', 'presence'])
+
+module.exports.getManyByRole = async (req, res) => {
+  try {
+    const docs = await User.find({ role: req.params.role }).lean().exec()
+
+    res.status(200).json({ data: docs.map((e) => pick(e, pickedKeys)) })
+  } catch (e) {
+    console.error(e)
+    res.status(400).end()
+  }
+}
 
 // Doesn't delete the user just disable it
-exports.default.softRemove = async (req, res) => {
+module.exports.softRemove = async (req, res) => {
   try {
     let user = await User.findOneAndUpdate(
-      { schacc: req.params.id },
+      { schacc: req.params.schacc },
       {
         valid: false,
         receiveMail: false,
@@ -83,19 +92,19 @@ exports.default.softRemove = async (req, res) => {
 
     return res
       .status(200)
-      .json({ data: pick(user, [...defaultKeys, 'bit', 'presence']) })
+      .json({ data: pick(user, [...pickedKeys, 'bit', 'presence']) })
   } catch (e) {
     console.error(e)
     return res.status(400).end()
   }
 }
 
-exports.default.updateOne = async (req, res) => {
+module.exports.updateOne = async (req, res) => {
   try {
-    if (!(req.params.id === req.user.schacc || req.user.role === 'mentor'))
+    if (!(req.params.schacc === req.user.schacc || req.user.role === 'mentor'))
       return res.status(403).end()
 
-    const userSchacc = req.params.id
+    const userSchacc = req.params.schacc
 
     // Update with given keys
     const updatedUser = await User.findOneAndUpdate(
@@ -114,8 +123,8 @@ exports.default.updateOne = async (req, res) => {
     // Pick keys
     let returnData
     if (req.user.role === 'mentor')
-      returnData = pick(updatedUser, [...defaultKeys, 'bit', 'presence'])
-    else returnData = pick(updatedUser, defaultKeys)
+      returnData = pick(updatedUser, [...pickedKeys, 'bit', 'presence'])
+    else returnData = pick(updatedUser, pickedKeys)
 
     return res.status(200).json({
       data: returnData,
diff --git a/src/resources/user/userDocs.yml b/src/resources/user/userDocs.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1a836b3532505d043001f9dd2b3e18d1bf83136f
--- /dev/null
+++ b/src/resources/user/userDocs.yml
@@ -0,0 +1,163 @@
+openapi: '3.0.2'
+info:
+  title: 'User Endpoint'
+  version: '1.0'
+
+paths:
+  /user:
+    get:
+      tags:
+        - 'User'
+      summary: 'Get a List of users'
+      description: 'This can only be done by a mentor.'
+      operationId: 'getAllUser'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: 'array'
+                items:
+                  $ref: '#/components/schemas/User'
+  /user/me:
+    get:
+      tags:
+        - 'User'
+      summary: 'Get own user'
+      description: 'Have to be logged in for this.'
+      operationId: 'getOwnUser'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/User'
+    put:
+      tags:
+        - 'User'
+      summary: 'Update own user'
+      description: 'Have to be logged in for this.'
+      operationId: 'updateOwnUser'
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/User'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/User'
+  /user/role/{role}:
+    get:
+      tags:
+        - 'User'
+      summary: 'Get a List of users by role'
+      description: 'This can only be done by a mentor.'
+      operationId: 'getAllUserByRole'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: 'array'
+                items:
+                  $ref: '#/components/schemas/User'
+  /user/schacc/{schacc}:
+    get:
+      tags:
+        - 'User'
+      summary: 'Get User by schacc'
+      description: 'This can only be done by a mentor or on own User.'
+      operationId: 'getOneUser'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/User'
+    put:
+      tags:
+        - 'User'
+      summary: 'Update a User by schacc'
+      description: 'This can only be done by a mentor or on own User.'
+      operationId: 'updateOneUser'
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/User'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/User'
+    delete:
+      tags:
+        - 'User'
+      summary: 'Delete User by schacc'
+      description: 'This can only be done by a mentor.
+        It only sets the valid and receiveMail field to false'
+      operationId: 'deleteOneUser'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/User'
+
+components:
+  schemas:
+    User:
+      type: object
+      properties:
+        internal_id:
+          type: string
+        schacc:
+          type: string
+        fullName:
+          type: string
+          maxLength: 50
+        secondaryEmail:
+          type: string
+          format: email
+        receiveMail:
+          type: boolean
+          default: true
+        nickName:
+          type: string
+          maxLength: 50
+        bit:
+          type: number
+          default: 0
+        presence:
+          type: number
+          default: 0
+        imagePath:
+          type: string
+        role:
+          type: string
+          enum:
+            - 'accepted'
+            - 'normal'
+            - 'mentor'
+          default: 'normal'
+        valid:
+          type: boolean
+          default: true
+      required:
+        - internal_id
+        - schacc
+        - fullName
+        - secondaryEmail
+        - role
+        - valid
diff --git a/src/resources/user/userModel.js b/src/resources/user/userModel.js
index 9c7ababac277b164d1195bd6d0c20943bde1d329..9321af1c6a800207c6366647313bdfd892cc5264 100644
--- a/src/resources/user/userModel.js
+++ b/src/resources/user/userModel.js
@@ -10,7 +10,7 @@ const UserSchema = new mongoose.Schema(
     schacc: {
       type: String,
       required: true,
-      unique: true,
+      index: { unique: true },
     },
     fullName: {
       type: String,
@@ -47,7 +47,6 @@ const UserSchema = new mongoose.Schema(
     },
     imagePath: {
       type: String,
-      required: false,
     },
     role: {
       type: String,
@@ -58,13 +57,12 @@ const UserSchema = new mongoose.Schema(
     valid: {
       type: Boolean,
       default: true,
+      required: true,
     },
   },
   { timestamps: true }
 )
 
-UserSchema.index({ schacc: 1 })
-
 const User = mongoose.model('user', UserSchema)
 
 exports.User = User
diff --git a/src/resources/user/userRouter.js b/src/resources/user/userRouter.js
index ca0638306c7ece2d9cb98fe5fd7e4f0cb4a794c7..583a0c920c50a3a8cbc16aa0c3d9e8726492d0cf 100644
--- a/src/resources/user/userRouter.js
+++ b/src/resources/user/userRouter.js
@@ -4,14 +4,29 @@ const { isLoggedIn, isMentor } = require('../../middlewares/auth')
 
 const router = Router()
 
-// /api/user
-router.route('/').get(isLoggedIn, isMentor, controllers.default.getMany)
+// /api/v1/user
+router.route('/').get(isLoggedIn, isMentor, controllers.getMany)
 
-// /api/user/:id
+// /api/v1/user/role/:role
+router.route('/role/:role').get(isLoggedIn, isMentor, controllers.getManyByRole)
+
+// /api/v1/user/schacc/:schacc
+router
+  .route('/schacc/:schacc')
+  .get(isLoggedIn, controllers.getOne)
+  .put(isLoggedIn, controllers.updateOne)
+  .delete(isLoggedIn, isMentor, controllers.softRemove)
+
+// /api/v1/user/me
 router
-  .route('/:id')
-  .get(isLoggedIn, controllers.default.getOne)
-  .put(isLoggedIn, controllers.default.updateOne)
-  .delete(isLoggedIn, isMentor, controllers.default.softRemove)
+  .route('/me')
+  .get(isLoggedIn, async (req, res) => {
+    req.params.schacc = req.user.schacc
+    await controllers.getOne(req, res)
+  })
+  .put(isLoggedIn, async (req, res) => {
+    req.params.schacc = req.user.schacc
+    await controllers.updateOne(req, res)
+  })
 
 exports.default = router
diff --git a/src/routers.js b/src/routers.js
index 3f2d01c8bd17d30d2f8c82959b28114069afa1e7..40d3d9832b1d74680481f04ab579874d2fa1387e 100644
--- a/src/routers.js
+++ b/src/routers.js
@@ -9,7 +9,6 @@ const commentRouter = require('./resources/comment/commentRouter')
 const attendanceRouter = require('./resources/attendance/attendanceRouter')
 const taskRouter = require('./resources/task/taskRouter')
 const settingsRouter = require('./resources/settings/settingsRouter')
-const extraRouter = require('./resources/extra/extraRouter')
 
 exports.routers = {
   userRouter: userRouter.default,
@@ -23,5 +22,4 @@ exports.routers = {
   attendanceRouter: attendanceRouter.default,
   taskRouter: taskRouter.default,
   settingsRouter: settingsRouter.default,
-  extraRouter: extraRouter.default,
 }
diff --git a/src/server.js b/src/server.js
index c315bc67bffecfb26edc4e2d534ae62da2e83787..37d8e4c37db5520faa7dec3db517d959cf0680eb 100644
--- a/src/server.js
+++ b/src/server.js
@@ -6,6 +6,8 @@ const cors = require('cors')
 const morgan = require('morgan')
 const passport = require('passport')
 const cookieSession = require('cookie-session')
+const swaggerJsdoc = require('swagger-jsdoc')
+const swaggerUi = require('swagger-ui-express')
 
 require('dotenv').config()
 
@@ -44,7 +46,7 @@ app.use(
 app.use(passport.initialize())
 app.use(passport.session())
 
-if (!config.default.isTest) {
+if (!config.default.isTest || config.default.isDev) {
   require('./utils/oauthSetup')
   app.get(
     '/api/v1/login/authsch',
@@ -96,6 +98,49 @@ app.get('/api/v1/logout', (req, res) => {
   res.redirect('/')
 })
 
+// Swagger
+const options = {
+  swaggerDefinition: {
+    openapi: '3.0.0',
+    info: {
+      title: 'Kszképzés Express Backend',
+      version: '1.0.0',
+      description: 'Backendje a képzést elősegítő weboldalnak',
+      license: {
+        name: 'MIT',
+        url: 'https://choosealicense.com/licenses/mit/',
+      },
+      contact: {
+        name: 'Swagger',
+        url: 'https://swagger.io',
+        email: 'Info@SmartBear.com',
+      },
+    },
+    servers: [
+      {
+        url: 'http://127.0.0.1:3000/api/v1',
+        url: 'https://ujonc.dev.donald.sch.bme.hu/api/v1',
+        url: 'https://ujonc.donald.sch.bme.hu/api/v1',
+      },
+    ],
+  },
+  apis: ['./src/resources/**/*.yml'],
+  securityDefinitions: {
+    auth: {
+      type: 'basic',
+    },
+  },
+  security: [{ auth: [] }],
+}
+const specs = swaggerJsdoc(options)
+app.use('/api/v1/swagger', swaggerUi.serve)
+app.get(
+  '/api/v1/swagger',
+  swaggerUi.setup(specs, {
+    explorer: true,
+  })
+)
+
 // API Routes
 app.use('/api/v1/user', routers.routers.userRouter)
 app.use('/api/v1/mentor', routers.routers.mentorRouter)
@@ -108,6 +153,5 @@ app.use('/api/v1/attendance', routers.routers.attendanceRouter)
 app.use('/api/v1/task', routers.routers.taskRouter)
 app.use('/api/v1/activity', routers.routers.activityRouter)
 app.use('/api/v1/settings', routers.routers.settingsRouter)
-app.use('/api/v1/extra', routers.routers.extraRouter)
 
 exports.app = app