diff --git a/.gitmodules b/.gitmodules
index 3dcc84ab394bd810993cf8adc0af0618b21db844..f612bc05fef311547b546e68da614a7aec463793 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,3 +4,6 @@
 [submodule "NodeApp/src/shared"]
 	path = NodeApp/src/shared
 	url = ../../shared/nodesharedcode.git
+[submodule "NodeApp/src/sharedByClients"]
+	path = NodeApp/src/sharedByClients
+	url = ../../shared/nodeclientsharedcode.git
diff --git a/NodeApp/src/commander/enonce/EnonceCreateCommand.ts b/NodeApp/src/commander/enonce/EnonceCreateCommand.ts
index 2228f7931bf7ca98c8a77b1ae76638fa3b3cdca3..6002d25561cf4194631c146bba7849a10cb7f9cf 100644
--- a/NodeApp/src/commander/enonce/EnonceCreateCommand.ts
+++ b/NodeApp/src/commander/enonce/EnonceCreateCommand.ts
@@ -4,14 +4,14 @@ import ora                from 'ora';
 import GitlabManager      from '../../managers/GitlabManager';
 import GitlabUser         from '../../shared/types/Gitlab/GitlabUser';
 import DojoBackendManager from '../../managers/DojoBackendManager';
-import Enonce             from '../../types/Enonce';
+import Enonce             from '../../sharedByClients/models/Enonce';
 import Toolbox            from '../../shared/helpers/Toolbox';
 import AccessesHelper     from '../../helpers/AccessesHelper';
 
 
 class EnonceCreateCommand extends CommanderCommand {
     protected commandName: string = 'create';
-    
+
     protected defineCommand() {
         this.command
         .description('create a new repository for an enonce')
diff --git a/NodeApp/src/commander/enonce/EnoncePublishUnpublishCommandBase.ts b/NodeApp/src/commander/enonce/EnoncePublishUnpublishCommandBase.ts
index 53c98217ee70544365cbcb8b0371f0f737b436d5..c94c419d6379fa0847e5f26e1b87e18068580b0a 100644
--- a/NodeApp/src/commander/enonce/EnoncePublishUnpublishCommandBase.ts
+++ b/NodeApp/src/commander/enonce/EnoncePublishUnpublishCommandBase.ts
@@ -1,6 +1,6 @@
 import CommanderCommand   from '../CommanderCommand';
 import inquirer           from 'inquirer';
-import Enonce             from '../../types/Enonce';
+import Enonce             from '../../sharedByClients/models/Enonce';
 import chalk              from 'chalk';
 import SessionManager     from '../../managers/SessionManager';
 import ora                from 'ora';
diff --git a/NodeApp/src/commander/exercice/ExerciceCreateCommand.ts b/NodeApp/src/commander/exercice/ExerciceCreateCommand.ts
index 3e637099fa76112e6fccae70a833ea7b83aefa70..ccd761f934eef858b8cc73aedb29eeca8b0755e6 100644
--- a/NodeApp/src/commander/exercice/ExerciceCreateCommand.ts
+++ b/NodeApp/src/commander/exercice/ExerciceCreateCommand.ts
@@ -2,10 +2,10 @@ import CommanderCommand   from '../CommanderCommand';
 import chalk              from 'chalk';
 import GitlabManager      from '../../managers/GitlabManager';
 import GitlabUser         from '../../shared/types/Gitlab/GitlabUser';
-import Enonce             from '../../types/Enonce';
+import Enonce             from '../../sharedByClients/models/Enonce';
 import ora                from 'ora';
 import DojoBackendManager from '../../managers/DojoBackendManager';
-import Exercice           from '../../types/Exercice';
+import Exercice           from '../../sharedByClients/models/Exercice';
 import AccessesHelper     from '../../helpers/AccessesHelper';
 
 
diff --git a/NodeApp/src/managers/DojoBackendManager.ts b/NodeApp/src/managers/DojoBackendManager.ts
index cb9d9eaf36b7bdcf548b6adc7abbf1fd6b552a7a..ce05f433df84c43c071a3ecf4fe93d355a5588d0 100644
--- a/NodeApp/src/managers/DojoBackendManager.ts
+++ b/NodeApp/src/managers/DojoBackendManager.ts
@@ -1,11 +1,11 @@
 import axios, { AxiosError } from 'axios';
 import Config                from '../config/Config';
 import ora                   from 'ora';
-import ApiRoutes             from '../types/ApiRoutes';
+import ApiRoutes             from '../sharedByClients/types/ApiRoutes';
 import { StatusCodes }       from 'http-status-codes';
-import Enonce                from '../types/Enonce';
+import Enonce                from '../sharedByClients/models/Enonce';
 import GitlabUser            from '../shared/types/Gitlab/GitlabUser';
-import Exercice              from '../types/Exercice';
+import Exercice              from '../sharedByClients/models/Exercice';
 import DojoResponse          from '../shared/types/DojoResponse';
 
 
diff --git a/NodeApp/src/managers/SessionManager.ts b/NodeApp/src/managers/SessionManager.ts
index ccf34ef43acdf39c40dccac24ad2aa59f76bc403..653d94e84d2479141a84fe97f9114260dfb3c831 100644
--- a/NodeApp/src/managers/SessionManager.ts
+++ b/NodeApp/src/managers/SessionManager.ts
@@ -1,12 +1,12 @@
 import * as jwt              from 'jsonwebtoken';
-import User                  from '../models/User';
+import User                  from '../sharedByClients/models/User';
 import LocalConfig           from '../config/LocalConfig';
 import LocalConfigKeys       from '../types/LocalConfigKeys';
 import axios, { AxiosError } from 'axios';
 import HttpManager           from './HttpManager';
 import ora                   from 'ora';
 import Permissions           from '../types/Permissions';
-import ApiRoutes             from '../types/ApiRoutes';
+import ApiRoutes             from '../sharedByClients/types/ApiRoutes';
 import DojoBackendManager    from './DojoBackendManager';
 import { StatusCodes }       from 'http-status-codes';
 
@@ -14,7 +14,7 @@ import { StatusCodes }       from 'http-status-codes';
 class SessionManager {
     private _token: string | null = null;
 
-    public profile: User = new User();
+    public profile: User | undefined = undefined;
 
     get isLogged(): boolean {
         return this._token !== null;
@@ -31,10 +31,10 @@ class SessionManager {
             const payload = jwt.decode(token);
 
             if ( payload && typeof payload === 'object' && payload.profile ) {
-                this.profile = User.createFromJson(payload.profile);
+                this.profile = payload.profile as User;
             }
         } catch ( error ) {
-            this.profile = new User();
+            this.profile = undefined;
         }
 
         LocalConfig.updateConfig(LocalConfigKeys.API_TOKEN, token);
@@ -43,7 +43,7 @@ class SessionManager {
     async login(user: string, password: string) {
         const spinner: ora.Ora = ora('Logging in').start();
         try {
-            this.profile = new User();
+            this.profile = undefined;
 
             const response = await axios.post(DojoBackendManager.getApiUrl(ApiRoutes.LOGIN), {
                 user    : user,
@@ -72,7 +72,7 @@ class SessionManager {
 
     checkPermissions(verbose: boolean = true, indent: number = 8, checkPermissions: Array<string> | null = []): Permissions {
         const hasPermission = (permissionPredicate: () => boolean, verboseText: string): boolean => {
-            let isAllowed: boolean = this.profile.id !== -1 && permissionPredicate();
+            let isAllowed: boolean = this.profile !== undefined && permissionPredicate();
 
             if ( verbose ) {
                 const spinner: ora.Ora = ora({
@@ -86,7 +86,7 @@ class SessionManager {
         };
 
         return {
-            teachingStaff: checkPermissions && (checkPermissions.length == 0 || checkPermissions.includes('teachingStaff')) ? hasPermission(() => this.profile.isTeachingStaff, 'Teaching staff permissions') : false,
+            teachingStaff: checkPermissions && (checkPermissions.length == 0 || checkPermissions.includes('teachingStaff')) ? hasPermission(() => this.profile?.isTeachingStaff ?? false, 'Teaching staff permissions') : false,
             student      : checkPermissions && (checkPermissions.length == 0 || checkPermissions.includes('student')) ? hasPermission(() => true, 'Student permissions') : false
         };
     }
diff --git a/NodeApp/src/models/Model.ts b/NodeApp/src/models/Model.ts
deleted file mode 100644
index 65949fba7e59ae9421274f9d25b61c8d1a15fb84..0000000000000000000000000000000000000000
--- a/NodeApp/src/models/Model.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-type Constructor<T> = new (...args: any[]) => T;
-
-
-abstract class Model extends Object {
-    static createFromJson<T extends Object>(this: Constructor<T>, obj: any): T {
-        const result = new this();
-
-        Object.getOwnPropertyNames(obj).forEach(property => {
-            if ( result.hasOwnProperty(property) ) {
-
-                (result as any)[property] = property.indexOf('Info') === -1 ? obj[property] : JSON.parse(obj[property]);
-            }
-        });
-        return result;
-    }
-}
-
-
-export default Model;
diff --git a/NodeApp/src/models/User.ts b/NodeApp/src/models/User.ts
deleted file mode 100644
index 5c06cc4679927b58c5a17a675c80b98113e44bea..0000000000000000000000000000000000000000
--- a/NodeApp/src/models/User.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import Model from './Model';
-
-
-class User extends Model {
-    id: number = -1;
-    firstName: string = '';
-    lastName: string = '';
-    mail: string = '';
-    gitlabId: number = -1;
-    role: string = '';
-    isTeachingStaff: boolean = false;
-    deleted: boolean = true;
-
-    constructor() {
-        super();
-    }
-
-    get fullName(): string {
-        return this.lastName.toUpperCase() + ' ' + this.firstName;
-    }
-}
-
-
-export default User;
diff --git a/NodeApp/src/sharedByClients b/NodeApp/src/sharedByClients
new file mode 160000
index 0000000000000000000000000000000000000000..3cd4b0c0e18fb8e8f52062cf4b171c8c67d4baea
--- /dev/null
+++ b/NodeApp/src/sharedByClients
@@ -0,0 +1 @@
+Subproject commit 3cd4b0c0e18fb8e8f52062cf4b171c8c67d4baea
diff --git a/NodeApp/src/types/ApiRoutes.ts b/NodeApp/src/types/ApiRoutes.ts
deleted file mode 100644
index 04c0ae614cc8d5d8e657463e92d766cc07f35db9..0000000000000000000000000000000000000000
--- a/NodeApp/src/types/ApiRoutes.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-enum ApiRoutes {
-    LOGIN                        = '/login',
-    TEST_SESSION                 = '/test_session',
-    GITLAB_CHECK_TEMPLATE_ACCESS = '/gitlab/project/{{id}}/checkTemplateAccess',
-    ENONCE_GET                   = '/enonces/{{nameOrUrl}}',
-    ENONCE_CREATE                = '/enonces',
-    ENONCE_PUBLISH               = '/enonces/{{nameOrUrl}}/publish',
-    ENONCE_UNPUBLISH             = '/enonces/{{nameOrUrl}}/unpublish',
-    EXERCICE_CREATE              = '/enonces/{{nameOrUrl}}/exercices',
-}
-
-
-export default ApiRoutes;
\ No newline at end of file
diff --git a/NodeApp/src/types/Enonce.ts b/NodeApp/src/types/Enonce.ts
deleted file mode 100644
index 43f37bd40b2aec49cf8b8713626a792d9365135a..0000000000000000000000000000000000000000
--- a/NodeApp/src/types/Enonce.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import GitlabRepository from '../shared/types/Gitlab/GitlabRepository';
-import User             from '../models/User';
-import Exercice         from './Exercice';
-
-
-interface Enonce {
-    name: string;
-    gitlabId: number;
-    gitlabLink: string;
-    gitlabCreationInfo: GitlabRepository;
-    gitlabLastInfo: GitlabRepository;
-    gitlabLastInfoDate: string;
-    published: boolean;
-
-    staff: Array<User>;
-    exercices: Array<Exercice>;
-}
-
-
-export default Enonce;
\ No newline at end of file
diff --git a/NodeApp/src/types/Exercice.ts b/NodeApp/src/types/Exercice.ts
deleted file mode 100644
index c2ce3d870cf2f3d4faabd59e612588e4469a7130..0000000000000000000000000000000000000000
--- a/NodeApp/src/types/Exercice.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import GitlabRepository from '../shared/types/Gitlab/GitlabRepository';
-
-
-interface Exercice {
-    id: string;
-    enonceName: string;
-    name: string;
-    gitlabId: number;
-    gitlabLink: string;
-    gitlabCreationInfo: GitlabRepository;
-    gitlabLastInfo: GitlabRepository;
-    gitlabLastInfoDate: string;
-}
-
-
-export default Exercice;
\ No newline at end of file