diff --git a/README.md b/README.md
index 65bc8e0d93f14328bb60376968f4688df8484fe4..208078bcac5c6cc3d5f07b35ce912ada66c45324 100644
--- a/README.md
+++ b/README.md
@@ -20,9 +20,9 @@ git clone https://gitlab.binets.fr/br/sigma-backend.git
 On utilise un serveur node.js avec [express.js](https://expressjs.com/). [^server]
 Utiliser Node.js permet d'utiliser facilement [*npm*](https://www.npmjs.com/) (Node Package Manager). Une "dépendance" est un package utilisé dans le projet.
 
-[^server]: il est configuré dans [`app.ts`](./src/app.ts) puis lancé sur le port 3000 dans [`index.ts`](./src/index.ts).
+[^server]: il est configuré dans [`app.ts`](./src/app.ts) puis lancé sur le port 3000 dans [`index.ts`](../src/index.ts).
 
-On trouve la liste des dépendances dans [`package.json`](./package.json). Express est un exemple de dépendance normale, utilisée en production ; nodemon et ESLint (voir infra) sont des dépendances dev (`devDependencies`), utilisées seulement en mode développement.
+On trouve la liste des dépendances dans [`package.json`](../package.json). Express est un exemple de dépendance normale, utilisée en production ; nodemon et ESLint (voir infra) sont des dépendances dev (`devDependencies`), utilisées seulement en mode développement.
 
 Les dépendances s'installent avec `npm install`. Cette commande a deux comportements possibles selon la valeur de la variable `NODE_ENV` (vérifier avec la commande `echo "$NODE_ENV"`):
 * si `NODE_ENV` n'est pas configuré : on installe tout
@@ -69,7 +69,7 @@ createdb sigma_dev -U sigma -W
 ```
 - Si vous n'arrivez pas à vous connecter (`createdb: could not connect to database template1: FATAL: Peer authentication failed for user`) : mettre à jour votre fichier `pg_hba.conf`. 
     - voir https://stackoverflow.com/questions/1471571/how-to-configure-postgresql-for-the-first-time
-- Si vous souhaitez utiliser d'autres noms que "sigma" et "sigma_dev" : ça ne pose pas de problème, il vous faudra simplement modifier `./db/knexfile.js` et `./db/knex_init.js`.
+- Si vous souhaitez utiliser d'autres noms que "sigma" et "sigma_dev" : ça ne pose pas de problème, il vous faudra simplement modifier `../db/knexfile.js` et `../db/knex_init.js`.
 
 Exécuter les *migrations* et les *seeds* de knex :
 ```bash
@@ -83,7 +83,7 @@ knex seed:run
 Voilà, vous avez une base de données à jour !
 
 ### Démarrer le serveur
-Dire à webpack de build le projet (build le bundle `./build/bundle.js`) :
+Dire à webpack de build le projet (build le bundle `../build/bundle.js`) :
 ```bash
 npm run dev # en mode developpement
 # ou
@@ -97,7 +97,7 @@ npm run start # ou le raccourci: npm start
 Comme indiqué dans src/index.js, ceci lance un serveur servant l'application express sur le port 3000. Ce serveur va ensuite éxecuter le reste du code comme si il était déployé ou presque.
 
 ## Alternative : déployer dans un conteneur Docker
-L'image Docker est définie dans [`Dockerfile`](./Dockerfile). Il s'agit d'une distro Alpine avec Node.js et libstdc++. Lors du _build_ les dépendances _runtime_ dont dépend le `bundle.js` sont installées.
+L'image Docker est définie dans [`Dockerfile`](../Dockerfile). Il s'agit d'une distro Alpine avec Node.js et libstdc++. Lors du _build_ les dépendances _runtime_ dont dépend le `bundle.js` sont installées.
 
 Compiler l'image :
 ```bash
@@ -117,7 +117,7 @@ TODO
 Ca a un rapport avec NODE_ENV ?
 
 ## Scripts
-Les scripts sont des instructions en ligne de commande que l'on peut faire tourner avec la commande `npm run`. Ce sont des raccourcis pour gagner du temps sur des opérations un peu longues. Ils sont définis dans [`package.json`](./package.json).
+Les scripts sont des instructions en ligne de commande que l'on peut faire tourner avec la commande `npm run`. Ce sont des raccourcis pour gagner du temps sur des opérations un peu longues. Ils sont définis dans [`package.json`](../package.json).
 
 Les plus importants sont détaillées ci-dessous :
 - `npm run build` : transpiler avec Webpack, en mode production
@@ -127,7 +127,7 @@ Les plus importants sont détaillées ci-dessous :
 - `npm run doc` : générer la doc JSDoc
 - `npm run lint` : vérifier la syntaxe de tous les fichiers .js et .ts du dossier src/
 
-`npm run start` démarre en fait le serveur buildé [`build/bundle.js`](build/bundle.js) avec [nodemon](https://nodemon.io/), un outil de dév qui le redémarre automatiquement après toute modification *du bundle*.
+`npm run start` démarre en fait le serveur buildé [`build/bundle.js`](../build/bundle.js) avec [nodemon](https://nodemon.io/), un outil de dév qui le redémarre automatiquement après toute modification *du bundle*.
 
 Donc, lancer `npm run watch` dans un terminal et `npm run start` dans un autre permet de rebuilder **et** relancer automatiquement le serveur, après toute modification *du code source*.
 
@@ -139,17 +139,19 @@ On peut donc le configurer via des fichiers ou des variables d'environnement.
 ### Configuration LDAP
 L'API de Sigma nécessite de se connecter au LDAP Frankiz, à la fois pour obtenir des données et pour l'authentification des utilisateurs. Cela est fait à l'aide de la librairie [ldapjs](http://ldapjs.org) pour faire les requêtes au LDAP et [passportJS](http://www.passportjs.org/) pour l'authentification.
 
-* La configuration LDAP de base se situe dans [ldap_config.json](ldap_config.json).
-* Les identifiants utilisés que authentifier le serveur au LDAP sont dans [ldap_credentials.json](./ldap_credentials.json). Ils prennent la forme suivante:
+* La configuration LDAP de base se situe dans [ldap_config.json](../ldap_config.json).
+* Les identifiants utilisés que authentifier le serveur au LDAP sont dans [ldap_credentials.json](../ldap_credentials.json). Ils prennent la forme suivante:
 ```json
 {
     "dn": "uid=<username>,ou=eleves,dc=frankiz,dc=net",
     "passwd": "<password>"
 }
 ```
-* Elle est importée dans l'application depuis [src/ldap/config.ts](src/ldap/config.ts).
+* Elle est importée dans l'application depuis [src/ldap/internal/config.ts](../src/ldap/internal/config.ts).
 * Si la variable d'environnement `LDAP_URI` est définie, l'adresse où trouver le LDAP est remplacée.
 
+Le LDAP de Frankiz est sous OpenLDAP, qui a l'avantage d'être largement utilisée, documentée sur Internet, compatible avec des lecteurs génériques comme [JXplorer](http://jxplorer.org/) et gérant ses propres logs (voir [ce blog](https://www.vincentliefooghe.net/content/openldap-gestion-des-logs)).
+
 **Exemple**
 
 Si on développe en dehors du plâtal et qu'on ouvre un proxy SSH avec _port forwarding_ du LDAP de Frankiz (<frankiz.polytechnique.fr:389>) vers <localhost:8389>, on s'y connecte en définissant : `LDAP_URI=ldap://localhost:8389`, soit en faisant `export LDAP_URI=...`, soit en écrivant un fichier `.env`. Le fichier `config.js` s'occupe du reste.
@@ -216,14 +218,14 @@ Les tests effectués sont dans test/testData.js, sous la forme d'une liste. Chaq
 [^doute_tests]: cette fonctionnalité n'a pas été utilisée ni testée depuis beaucoup trop de commits pour que cette partie soit fiable actuellement (2018-12-04).
 
 ## Documentation
-La documentation détaillée du projet est [ici](./doc/index.html). Elle a été compilée avec [JSDoc](http://usejsdoc.org/index.html) sous format hmtl selon le fichier de configuration [`configfile_doc.json`](./configfile_doc.json) à la racine du projet.
+La documentation détaillée du projet est [ici](index.html). Elle a été compilée avec [JSDoc](http://usejsdoc.org/index.html) sous format hmtl selon le fichier de configuration [`configfile_doc.json`](./configfile_doc.json) à la racine du projet.
 
-Le script pour faire tourner [JSDoc](http://usejsdoc.org/index.html) et régénérer la documentation est : `npm run doc`
+Le script pour faire tourner [JSDoc](http://usejsdoc.org/index.html) et régénérer la documentation est : `npm run doc`. Les liens ett images sont faits pour fonctionner en local, donc ne vous étonnez pas si vous avez des surprises en regardant ce README depuis git.
 
 Les fichiers compilés se situent dans [`doc`](.) avec leurs fichiers image. Par nature de l'outil JSDoc il est facile de documenter en détail des fonctions .js mais plus compliqué de documenter un fichier.
 
-A chaque execution JSDoc rajoute les commentaires placés dans chacun des fichiers dans la doc de façon structurée.
+A chaque execution JSDoc rajoute les commentaires placés dans chacun des fichiers dans la doc de façon structurée. Les notes en Markdown placés dans notes/ sont également rajoutées en tant que tutoriels (voir {@tutorial CONTRIBUTING}).
 
 La structure générale du projet peut être résumé comme suit :
 
-![alt text](assets/struct.png "Structure du projet")
\ No newline at end of file
+![struct_projet](../assets/struct.png "Structure du projet")
\ No newline at end of file
diff --git a/configfile_doc.json b/configfile_doc.json
index 790ec5f9bec701e6f710eb75495886408596b51a..72d6252e2583dcfcfcddc8728f6fbf8d36bab67d 100644
--- a/configfile_doc.json
+++ b/configfile_doc.json
@@ -3,7 +3,7 @@
     "plugins": ["plugins/markdown", "plugins/summarize", "node_modules/jsdoc-babel"],
     "recurseDepth": 5,
     "source": {
-        "include": ["./README.md","./CONTRIBUTING.md","./src","./test","./db"],
+        "include": ["./README.md","./src","./test","./db"],
         "exclude": [],
         "includePattern": "(.+\\.(js|ts)(doc|x)?$)|(.md)",
         "excludePattern": "((^|\\/|\\\\)_)|(20|0)"
@@ -13,7 +13,8 @@
         "template": "templates/default",
         "encoding": "utf8",             
         "destination": "./doc",        
-        "recurse": true
+        "recurse": true,
+        "tutorials": "./notes"
     },
     "tags": {
         "allowUnknownTags": true,
diff --git a/db/knex_router.js b/db/knex_router.ts
similarity index 99%
rename from db/knex_router.js
rename to db/knex_router.ts
index 8911c2eae70bb922c2c31252cc2c91ce6c6f7711..999fb9b3c8cb778e8b9191329bf07fff8d2b6a39 100644
--- a/db/knex_router.js
+++ b/db/knex_router.ts
@@ -1,6 +1,6 @@
 /**
  * @file Charge la configuration knexjs adaptée à l'environnement (production ou développement) puis exporte un objet knex permettant les requêtes SQL
-*/
+ */
 require('dotenv').config();
 
 const environment = process.env.TARGET_ENV || 'development';
diff --git a/db/knexfile.js b/db/knexfile.js
index dc6a3c7b5f3bf27855823251f975be9c346e545e..a439284e0e14dd16e2a64f497ccb8cbe580687f0 100644
--- a/db/knexfile.js
+++ b/db/knexfile.js
@@ -1,5 +1,5 @@
 /**
- * * @file Fichier de configuration Knex. Il spécifie la base de donnée à laquelle se connecter, son adresse, le nom 
+ * @file Fichier de configuration Knex. Il spécifie la base de donnée à laquelle se connecter, son adresse, le nom 
  * d'un utilisateur sur le serveur qui a les droits appropriés, et son mot de passe.
  * 
  * Le fichier précise également où stocker les fichiers de migrations Knex ainsi que les _seeds_.
diff --git a/ldap_config.json b/ldap_config.json
index 03484ee0cd6facfe2060d30a43f8ced9107d6672..c8a32ccff2f37e7881d6152e38e7b971a2362308 100644
--- a/ldap_config.json
+++ b/ldap_config.json
@@ -1,7 +1,8 @@
 {
 	"comment_1": "Tout ce fichier sert à protéger les vrais champs du LDAP dans les scripts dans src/ldap. Les champs ci-dessous contiennent le nécessaire à une première connexion par exemple.",
-	"server": "ldap://frankiz.eleves.polytechnique.fr:389",
-	
+	"server_prod": "ldap://frankiz.eleves.polytechnique.fr:389",
+	"server_dev": "???",
+
 	"comment_2": "Noms de domaines dans LDAP ; le niv d'après est en uid=, voir Wikipedia",
 	"dn_groups":"ou=groups,dc=frankiz,dc=net",
 	"dn_users": "ou=eleves,dc=frankiz,dc=net",
diff --git a/notes/CONTRIBUTING.json b/notes/CONTRIBUTING.json
new file mode 100644
index 0000000000000000000000000000000000000000..73e4bf55f475b71c5253066d9a8aed1f88250788
--- /dev/null
+++ b/notes/CONTRIBUTING.json
@@ -0,0 +1,7 @@
+{
+    "title": "Contribuer au projet",
+    "children": [
+        "memo_knexjs",
+        "memo_postgresql"
+    ]
+}
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/notes/CONTRIBUTING.md
similarity index 98%
rename from CONTRIBUTING.md
rename to notes/CONTRIBUTING.md
index f8f76d23262f54e04c391d16d62e9b1b418e4976..6d12e1a84aad664c390a64f3ea2a821ca4d4e8db 100644
--- a/CONTRIBUTING.md
+++ b/notes/CONTRIBUTING.md
@@ -1,6 +1,3 @@
-Contribuer au projet
-===
-
 Documentation haut-niveau, décrivant le projet du point de vue développeur de façon globale, sans rentrer dans le détail du code. 
 
 Il y a aussi une documentation plus précise, générée par JSDoc à partir des commentaires dans le code-même. Pour la générer, exécuter `npm run doc`. Elle sera alors [disponible dans ./doc](./doc/index.html). 
@@ -38,7 +35,7 @@ Certaines anciennes branches, fraîchement mergées, sont décrites ci-dessous.
 
 #### LDAP-refacto
 
-- TODO (@hawkspar tu peux expliquer ici a quoi sert cette branche  ? et le cas échéant, la merge dans master ?)
+Branche obsolète à supprimer.
 
 #### unit-tests
 
@@ -103,12 +100,12 @@ Cette structure peut sembler lourde et redondante mais s'explique par plusieurs
   - Le LDAP contient des informations plus sensibles (c'est là que toutes les données sur les utilisateurs sont stockées)
 
 ### Utiliser la BDD sigma avec *Knex.js*
-cf. [le memo knexjs](./memo\ knexjs.md).
+cf. {@tutorial memo_knexjs}.
 
 Le knexfile.js et le knex_router.js sont dans `./db`. La localisation des dossiers [seeds](./db/seeds) et [migrations](./db/migrations), est spécifiée dans le knexfile.js, en l'occurrence également dans `./db`.
 
 ### Interagir directement avec la BDD sigma en *PostgreSQL*
-cf. [le memo postgresql](./memo\ postgresql.md).
+cf. {@tutorial memo_postgresql}.
 
 Pour accéder à la "vraie" BDD, sur roued (le serveur qui héberge sigma), il faut
 
@@ -202,4 +199,4 @@ dans une autre pour avoir un environnement de développement agréable.
 ## Contact
 
 Le BR 2016, plus particulièrement Wilson Jallet, Guillaume Wang, Quentin Chevalier et Anatole Romon
-Le BR 2017, plus particulièrement Olivér Facklam
+Le BR 2017, plus particulièrement Olivér Facklam, Grégoire truc et Hardien Renaud
diff --git a/notes/memo_knexjs.json b/notes/memo_knexjs.json
new file mode 100644
index 0000000000000000000000000000000000000000..887d74bb75b48c0b7860316a35d9489ce39a1f51
--- /dev/null
+++ b/notes/memo_knexjs.json
@@ -0,0 +1,4 @@
+{
+    "title": "Memo knew.js",
+    "children": []
+}
\ No newline at end of file
diff --git a/db/memo_knexjs.md b/notes/memo_knexjs.md
similarity index 100%
rename from db/memo_knexjs.md
rename to notes/memo_knexjs.md
diff --git a/notes/memo_postgresql.json b/notes/memo_postgresql.json
new file mode 100644
index 0000000000000000000000000000000000000000..5854303fa10a833546c5fe97ea09c1a1805ddb0b
--- /dev/null
+++ b/notes/memo_postgresql.json
@@ -0,0 +1,4 @@
+{
+    "title": "Memo PostgreSQL",
+    "children": []
+}
\ No newline at end of file
diff --git a/db/memo_postgresql.md b/notes/memo_postgresql.md
similarity index 100%
rename from db/memo_postgresql.md
rename to notes/memo_postgresql.md
diff --git a/src/ldap/export/group.ts b/src/ldap/export/group.ts
index e7cba6a318342ad2ac905f2b00dd7c4c93f5987c..7f9f11f9d4fd12d7600e67f40942113339a0646d 100644
--- a/src/ldap/export/group.ts
+++ b/src/ldap/export/group.ts
@@ -1,11 +1,11 @@
 /**
- * @file Ce fichier contient la classe de l'API du LDAP qui gère les opérations sur les groupes.
+ * @file Ce fichier contient la classe de l'API du LDAP qui gère les opérations sur les groupes. Elle est destinée à être exportée pour être utilisée par les resolvers.
  * @author hawkspar
  */
 
 import {ldapConfig} from '../internal/config';
-import {LDAP} from '../internal/basics';
-import {Tools} from '../internal/utilities';
+import {Basics} from '../internal/basics';
+import {Tools} from '../internal/tools';
 
 /**
  * @interface groupData
@@ -31,12 +31,15 @@ export interface groupData {
 
 export class Group {
     /**
-     * @class Cette classe est une des deux classes exportables permettant de faire des opérations sur les groupes.
+     * @memberof LDAP
+     * @class Group
+     * @classdesc Cette classe est une des deux classes exportables permettant de faire des opérations sur les groupes.
      * @summary Constructeur vide.
-    */
+     */
     constructor() {}
      
     /**
+     * @memberof LDAP
      * @summary Fonction qui renvoit toutes les infos relatives à un groupe particulier.
      * @desc Cette fonction utilise {@link Tools.peek} avec l'interface {@link groupData}.
      * @arg {string} gid - Identifiant du groupe
@@ -54,6 +57,7 @@ export class Group {
     }
 
     /**
+     * @memberof LDAP
      * @summary Fonction qui retrouve le groupe qui ressemblent à l'input et qui correspond au type fourni. Etape 0 vers un vrai TOL (Trombino On Line) pour les groupes.
      * @desc Cette fonction utilise {@link Tools.search}.
      * @arg {groupData} input - String entré par l'utilisateur qui ressemble au nom du groupe.
@@ -71,6 +75,7 @@ export class Group {
     }
 
     /**
+     * @memberof LDAP
      * @summary Fonction qui permet d'ajouter un utilisateur à un groupe.
      * @desc Cette fonction fait essentiellement appel à {@link Tools.getMembers}, {@link Tools.getGroups} et {@link LDAP.change}.
      * @arg {string} uid - Identifiant de l'utilisateur à ajouter
@@ -87,7 +92,7 @@ export class Group {
                 let vals = {};
                 vals[ldapConfig.group.members] = uid;
                 // Erreur si pb lors de la modification
-                if (!await LDAP.change("gr", gid, "add", vals)) {
+                if (!await Basics.change("gr", gid, "add", vals)) {
                     throw "Erreur lors de la modification dans l'arbre des groupes pour ajouter un membre.";
                 }
             }
@@ -102,7 +107,7 @@ export class Group {
                 let vals2 = {};
                 vals2[ldapConfig.user.groups] = gid;
                 // Erreur si pb lors de la modification
-                if (!await LDAP.change("us", uid, "add", vals2)) {
+                if (!await Basics.change("us", uid, "add", vals2)) {
                     throw "Erreur lors de la modification dans l'arbre des utilisateurs pour ajouter un membre.";
                 }
             }
@@ -114,6 +119,7 @@ export class Group {
     }
 
     /**
+     * @memberof LDAP
      * @summary Fonction qui permet de supprimer un membre existant d'un groupe.
      * @desc Cette fonction fait essentiellement appel à {@link Tools.getMembers}, {@link Tools.getGroups} et {@link LDAP.change}.
      * @arg {string} uid - Identifiant de l'ex-membre
@@ -128,7 +134,7 @@ export class Group {
             let lm = await Tools.getMembers(gid);
             if (lm.includes(uid)) {
                 // Supprime tous les utilisateurs
-                if (!await LDAP.change("gr", gid, "del", ldapConfig.group.members)) {
+                if (!await Basics.change("gr", gid, "del", ldapConfig.group.members)) {
                     throw "Erreur lors de la suppression de tous les membres du groupe.";
                 }
                 // Les rajoute un par un, sauf pour le supprimé
@@ -149,7 +155,7 @@ export class Group {
             // Vérifie que l'utilisateur est pas déjà viré pour users
             if (lg.includes(gid)) {
                 // Supprime tous les groupes
-                if (!await LDAP.change("us", uid, "del", ldapConfig.user.groups)) {
+                if (!await Basics.change("us", uid, "del", ldapConfig.user.groups)) {
                     throw "Erreur lors de la suppression de tous les groupes du membre.";
                 }
                 // Les rajoute un par un, sauf pour le supprimé
@@ -169,6 +175,7 @@ export class Group {
     }
 
     /**
+     * @memberof LDAP
      * @summary Fonction qui permet de promouvoir un membre au stade d'administrateur d'un groupe.
      * @desc Cette fonction fait essentiellement appel à {@link Group.addMember} {@link Tools.getAdmins} et {@link LDAP.change}. Elle n'autorise pas
      * les doublons et opère dans les deux dns users et groups.
@@ -187,7 +194,7 @@ export class Group {
                 // Finalement modification, uniquement dans groups
                 let vals = {};
                 vals[ldapConfig.group.admins] = uid;
-                if (!await LDAP.change("gr", gid, "add", vals)) {
+                if (!await Basics.change("gr", gid, "add", vals)) {
                     throw "Erreur lors de l'ajout de l'admin dans l'arbre des groupes.";
                 }
             }
@@ -199,6 +206,7 @@ export class Group {
     }
 
     /**
+     * @memberof LDAP
      * @summary Fonction qui permet de rétrograder un membre du stade d'administrateur d'un groupe au stade d'utilisateur.
      * @desc Cette fonction fait essentiellement appel à {@link Group.remMember}, {@link Group.addMember} {@link LDAP.change}.
      * Rajoute l'utilisateur au groupe par effet de bord si l'utilisateur n'est pas administrateur.
@@ -216,7 +224,7 @@ export class Group {
             let la = await Tools.getAdmins(gid);
             if (la.includes(uid)) {
                 // Supprime tous les administrateurs
-                if (!await LDAP.change("gr", gid, "del", ldapConfig.group.admins)) {
+                if (!await Basics.change("gr", gid, "del", ldapConfig.group.admins)) {
                     throw "Erreur dans la suppression de tous les admins pour en supprimer un.";
                 }
                 // Les rajoute un par un, sauf pour le supprimé
@@ -233,6 +241,7 @@ export class Group {
         }
     }
     /**
+     * @memberof LDAP
      * @summary Fonction qui créé un nouveau groupe dans le LDAP.
      * @desc Cette fonction fait une utilisation massive d'eval pour anonymiser son code ; c'est mal et cela suppose que beaucoup de soins ont été pris lors de
      * l'escape de ses paramètres. Appelle {@link LDAP.add} et {@link LDAP.change}, mais aussi {@link Group.addMember} et {@link Group.addAdmin}
@@ -263,7 +272,7 @@ export class Group {
         for (let key_att in data) { vals[ldapConfig.group[key_att]]=data[key_att] };
 
         // Appel à la fonction de base
-        if (!await LDAP.add("gr", vals)) {
+        if (!await Basics.add("gr", vals)) {
             throw "Erreur lors de la création d'une nouvelle feuille dans l'arbre des groupes.";
         }
         // Certains champs nécessitent de petits calculs
@@ -299,14 +308,14 @@ export class Group {
         vals2[ldapConfig.group['writePerm']] = '!*';
 
         // Inscription des valeurs calculées par effet de bord
-        if (!await LDAP.change("gr", gid, "add", vals2)) {
+        if (!await Basics.change("gr", gid, "add", vals2)) {
             throw "Erreur lors de l'ajout des valeurs intelligentes du nouveau groupe.";
         }
 
         ["posixAccount", "posixGroup", "brAccount"].forEach(cst => {
             let vals3={};
             vals3[ldapConfig.group['classes']]=cst;
-            LDAP.change("gr", gid, "add", vals3).then(res => {
+            Basics.change("gr", gid, "add", vals3).then(res => {
                 if (!res) { throw "Erreur lors de l'ajout des valeurs constantes du nouveau groupe."; }
             });
         });
@@ -326,6 +335,7 @@ export class Group {
     }
 
     /**
+     * @memberof LDAP
      * @summary Fonction qui supprime un groupe du LDAP.
      * @desc Cette fonction commence par gérer les groupes du membre puis le supprime entièrement. A modifier une fois que le LDAP incluerait les groupes administres par une utilisateur.
      * Appelle {@link LDAP.clear} bien sûr, mais aussi {@link Group.remMember} et {@link Group.remAdmin} pour gérer les groupes de l'utilisateur sortant.
@@ -345,7 +355,7 @@ export class Group {
                 // Vérifie que l'utilisateur est pas déjà viré pour users
                 if (lg.includes(gid)) {
                     // Supprime tous les groupes
-                    if (!await LDAP.change("us", uid, "del", ldapConfig.user.groups)) {
+                    if (!await Basics.change("us", uid, "del", ldapConfig.user.groups)) {
                         throw "Erreur lors de la suppression de tous les groupes du membre.";
                     }
                     // Les rajoute un par un, sauf pour le supprimé
@@ -359,7 +369,7 @@ export class Group {
                 }
             });
             // Elimination
-            if (!await LDAP.clear("gr",gid)) { throw "Erreur lors de la suppression de la feuille dans l'arbre des groupes."; }
+            if (!await Basics.clear("gr",gid)) { throw "Erreur lors de la suppression de la feuille dans l'arbre des groupes."; }
             return true;
         }
         catch(err) {
@@ -368,6 +378,7 @@ export class Group {
     }
 
     /**
+     * @memberof LDAP
      * @summary Fonction qui édite un groupe existant dans le LDAP. Sans influence sur ses membres ou admins. 
      * @desc Appelle {@link Tools.edit}.
      * @arg {groupData} data - Dictionnaire des informations du groupe.
diff --git a/src/ldap/export/user.ts b/src/ldap/export/user.ts
index 5d9131a01d5d2c00addad8447f710c9c5cdbd19f..b50f668b223274b1a78734d7504357ea9488378b 100644
--- a/src/ldap/export/user.ts
+++ b/src/ldap/export/user.ts
@@ -1,12 +1,11 @@
 /**
- * @file Ce fichier regroupe les différentes classes avec différents utilisateurs. Ces classes sont dédiées à être exportées directement pour être utilisées par le solver.
- * Le découpage par fichier est arbitraire mais permet de regrouper certaines classes proches.
+ * @file Ce fichier contient la classe de l'API du LDAP qui gère les opérations sur les groupes. Elle est destinée à être exportée pour être utilisée par les resolvers.
  * @author hawkspar
  */
 
 import {ldapConfig} from '../internal/config';
-import {LDAP} from '../internal/basics';
-import {Tools} from '../internal/utilities';
+import {Basics} from '../internal/basics';
+import {Tools} from '../internal/tools';
 import {Group} from './group';
 
 /**
@@ -65,12 +64,15 @@ export interface userData {
 
 export class User {
     /**
-     * @class Cette classe est une des deux classes exportables permettant de faire des opérations sur les utilisateurs.
+     * @memberof LDAP
+     * @class User
+     * @classdesc Cette classe est une des deux classes exportables permettant de faire des opérations sur les utilisateurs.
      * @summary Constructeur vide.
      */
     constructor() {}
      
     /**
+     * @memberof LDAP
      * @summary Fonction qui renvoit les infos de base relatives à un utilisateur particulier.
      * @desc Cette fonction utilise {@link Tools.peek} avec l'interface {@link userData}.
      * @arg {string} uid - Identifiant de l'utilisateur, supposé valide.
@@ -88,6 +90,7 @@ export class User {
     }
     
     /**
+     * @memberof LDAP
      * @summary Fonction qui retrouve les uid des paxs validant les critères de recherche. Utiliser {@link User.peek} au cas par cas après pour obtenir les vraies infos.
      * @desc Cette fonction utilise {@link Tools.search}.
      * @arg {userData} data - Dictionnaire contenant les données nécessaires à la recherche. Les valeurs sont celles entrées par l'utilisateur et sont par hypothèse
@@ -107,6 +110,7 @@ export class User {
     }
     
     /**
+     * @memberof LDAP
      * @summary Fonction qui créé un nouvel utilisateur dans le LDAP.
      * @desc Appelle {@link LDAP.add} bien sûr, mais aussi {@link Group.addMember} et {@link Group.addAdmin} pour gérer les groupes du nouvel utilisateur.
      * @arg {fullUserData} data - Dictionnaire des informations utilisateurs. Des erreurs peuvent apparaître si tous les champs ne sont pas remplis.
@@ -137,7 +141,7 @@ export class User {
         }
 
         // Appel à la fonction de base
-        if (!await LDAP.add("us", vals)) { throw "Erreur de l'ajout de la feuille à l'arbre utilisateur."; }
+        if (!await Basics.add("us", vals)) { throw "Erreur de l'ajout de la feuille à l'arbre utilisateur."; }
         
         for (let key_att in data) {
             // Modifications multiples pour avoir plusieurs champs de même type ; boucle sur les attributs multiples
@@ -146,7 +150,7 @@ export class User {
                 data[key_att].forEach(val => {
                     let vals2 = {};
                     vals2[ldapConfig.user[key_att]]=val;
-                    LDAP.change("us", uid, "add", vals2).then(res => {
+                    Basics.change("us", uid, "add", vals2).then(res => {
                         if (!res) { throw "Erreur lors de l'ajout d'une valeur pour un champ à valeurs multiples à la feuille du nouvel utilisateur."; }
                     });
                 });
@@ -195,14 +199,14 @@ export class User {
         vals3[ldapConfig.user['idNum']] ='5000';
 
         // Inscription des valeurs calculées
-        if (!await LDAP.change("us", uid, "add", vals3)) {
+        if (!await Basics.change("us", uid, "add", vals3)) {
             throw "Erreur lors de l'ajout des valeurs calculées à la feuille du nouvel utilisateur.";
         }
 
         ["posixAccount", "shadowAccount", "inetOrgPerson", "brAccount"].forEach(cst => {
             let val3={};
             vals3[ldapConfig.user['class']]=cst;
-            LDAP.change("us", uid, "add", vals3).then(res => {
+            Basics.change("us", uid, "add", vals3).then(res => {
                 if (!res) { throw "Erreur lors de l'ajout d'une valeur constante à la feuille du nouvel utilisateur."; }
             });
         });
@@ -214,6 +218,7 @@ export class User {
     //------------------------------------------------------------------------------------------------------------------------
     
     /**
+     * @memberof LDAP
      * @summary Fonction qui supprime un utilisateur du LDAP.
      * @desc Cette fonction commence par gérer les groupes du membre puis le supprime entièrement.
      * Appelle {@link LDAP.clear} bien sûr, mais aussi {@link Group.remMember} et {@link Group.remAdmin} pour gérer les groupes de l'utilisateur sortant.
@@ -233,7 +238,7 @@ export class User {
                 let lm = await Tools.getMembers(gid);
                 if (lm.includes(uid)) {
                     // Supprime tous les membres
-                    if (!await LDAP.change("gr", gid, "del", ldapConfig.group.members)) {
+                    if (!await Basics.change("gr", gid, "del", ldapConfig.group.members)) {
                         throw "Erreur lors de la suppression de tous les membres du groupe.";
                     }
                     // Les rajoute un par un, sauf pour le supprimé
@@ -251,11 +256,12 @@ export class User {
             throw "Erreur lors de l'obtention des informations de l'utilisateur à supprimer.";
         }
         // Elimination
-        if (!LDAP.clear("us", uid)) { throw "Erreur lors de la suppression de l'utilisateur."; }
+        if (!Basics.clear("us", uid)) { throw "Erreur lors de la suppression de l'utilisateur."; }
         return true;
     }
 
     /**
+     * @memberof LDAP
      * @summary Fonction qui édite un utilisateur existant dans le LDAP.
      * @desc Appelle simplement {@link Tools.edit}. Sans effet sur les groupes de l'utilisateur concerné.
      * @arg {userData} data - Dictionnaire des informations utilisateurs
diff --git a/src/ldap/internal/basics.ts b/src/ldap/internal/basics.ts
index 8135f1aa4b2bec05a2a5d981987336bd29db257f..b96736d52a7376356c2580e6cc5b3194b12b0717 100644
--- a/src/ldap/internal/basics.ts
+++ b/src/ldap/internal/basics.ts
@@ -3,7 +3,6 @@
  * C'est ici que tout le filtrage est opéré, au plus bas niveau.
  * Toutes les fonctions écrites ici sont asynchrones et renvoient des Promises ce qui nécessite de les appeler avec la synthaxe
  * un peu particulière `f(args).then(res => ...)` pour exploiter leur résultat.
- * Le découpage par fichier est arbitraire mais permet de regrouper certaines classes proches.
  * @author hawkspar
  */
 
@@ -13,12 +12,10 @@ import ldapEscape from 'ldap-escape';
 // Fichier de ldapConfig du ldap
 import {ldapConfig, credentialsLdapConfig} from './config';
 
-// Important ; permet de vérifier que l'utilisateur reste connecté.
-//var ensureLoggedin =  require('connect-ensure-login').ensureLoggedIn; //hawkspar->manifold : est-ce encore utile ? je ne crois pas
-
 // Connection au serveur LDAP avec des temps de timeout arbitraires
 var client = ldap.createClient({ url: ldapConfig.server});
 
+// Interface pratique pour que Typescript comprenne ce qu'est un dictionnaire simple
 interface dic {
     [Key: string]: string;
 }
@@ -27,14 +24,17 @@ interface dic {
 // Fonctions de base agissant sur le LDAP
 //------------------------------------------------------------------------------------------------------------------------
 
-export class LDAP {
+export class Basics {
     /**
-     * @class Cette classe est la brique de base du fichier tout entier puisqu'elle contient les functions qui agissent directement sur le LDAP.
+     * @class Basics
+     * @classdesc Cette classe est la brique de base du fichier tout entier puisqu'elle contient les functions qui agissent directement sur le LDAP.
+     * @memberof LDAP
      * @summary Constructeur vide.
-    */
+     */
     constructor() {}
 
     /**
+     * @memberof LDAP
      * @summary Fonction qui sert à s'identifier sur le LDAP.
      * @desc Assez important en terme de sécurité, de gestion de conflit, et de droit d'accès. Méthode ldapjs 
      * (voir [`Client API`](http://ldapjs.org/client.html) méthode bind).
@@ -58,70 +58,96 @@ export class LDAP {
     }
 
     /**
+     * @memberof LDAP
      * @summary Fonction qui sert à s'identifier sur le LDAP avec plein pouvoirs.
      * @desc Appelle {@link bind} avec un utilisateur tout puissant.
      * @returns {Promise(boolean)} `true` si l'opération s'est bien déroulée, `false` sinon.
      * @static
      * @async
      */
-    static async adminBind() : Promise<boolean> { return LDAP.bind(credentialsLdapConfig.dn, credentialsLdapConfig.password); }
+    static async adminBind() : Promise<boolean> { return Basics.bind(credentialsLdapConfig.dn, credentialsLdapConfig.password); }
 
     /**
+     * @memberof LDAP
      * @summary Fonction qui sert à se déconnecter du LDAP.
      * @desc Assez important en terme de sécurité, de gestion de conflit, et de droit d'accès.
-     * Fait appel à {@link LDAP.bind} avec deux champs vides.
+     * Fait appel à {@link Basics.bind} avec deux champs vides.
      * @returns {Promise(boolean)} `true` si l'opération s'est bien déroulée, `false` sinon.
      * @static
      * @async
      */
-    static async unbind() : Promise<boolean> { return LDAP.bind("", ""); }
+    static async unbind() : Promise<boolean> { return Basics.bind("", ""); }
     
+
     /**
-     * @summary Fonction qui interroge le LDAP selon un protocole spécifié en argument et renvoit une liste de valeurs trouvées.
+     * @callback entryHandler
+     * @arg entry {*} - Convoluted ldap.js search result object
+     */
+
+    /**
+     * @memberof LDAP
+     * @summary Fonction qui interroge le LDAP selon un protocole spécifié en argument et modifie une liste pour y insérer les valeurs trouvées.
      * @desc Cette fonction utilise ldapjs (voir [`Client API`](http://ldapjs.org/client.html) méthode search). Cette fonction fait une demande au LDAP
      * qu'elle filtre selon un schéma prédéfini dans `filter` et à chaque résultat (event SearchEntry) le met dans une liste, et renvoit la liste à l'issue (event end).
      * @arg {'gr'|'us'} domain - Emplacement de la requête (groupe ou utilisateur)
-     * @arg {string} attribute - Attribut unique à renvoyer
+     * @arg {string[]} attributes - Attributs à renvoyer
      * @arg {string} id [null] - Identifiant facultatif pour une recherche triviale en o(1)
      * @arg {string} filter ["(objectClass=*)"] - Filtre logique de la recherche (format [`RFC2254`](https://tools.ietf.org/search/rfc2254)) déjà passé au ldapEscape
-     * @return {Promise(string[])} Résultats de la recherche ; soit une liste de valeurs d'attributs, 
-     * soit une liste de dictionnaires si on veut plus d'un attribut (les clés du dictionnaire sont celles du LDAP)
+     * @arg {entryHandler} handler - Wrapper pour gérer les requêtes simples ou multiples
+     * @return {void} Utilise handler pour gérer ses résultats au fur et à mesure
      * @static
      * @async
      */
-    static async searchSingle(domain: 'gr'|'us', attribute: string, id: string=null, filter: string="(objectClass=*)") : Promise<string[]> {
-        LDAP.adminBind();
+    static search(domain: 'gr'|'us', attributes: string[], id: string, filter: string, handler : (entry: any) => void) : void {
+        Basics.adminBind();
         let dn ="";
         if (id != null)     { dn+=ldapConfig.key_id+'='+id+','; }
         if (domain == "gr") { dn+=ldapConfig.dn_groups; }
         else                { dn+=ldapConfig.dn_users; }
-        let vals=[];
         // Interrogation LDAP selon filter
-        client.search(ldapEscape.dn("${txt}", { txt: dn}), {
+        client.search(ldapEscape.dn("${txt}", { txt: dn}), {            // Must be escaped in case of a malignious false id
             "scope": "sub",
-            "filter": ldapEscape.filter("${txt}", { txt: filter}),
-            "attributes": [attribute]
+            "filter": ldapEscape.filter("${txt}", { txt: filter}),      // Must be escaped in case of a malignious search arg
+            "attributes": attributes
         }, (err, res) => {
             // Gestion erreur ; pb car pas simple true / autre en sortie
             if (err) {
                 throw "Erreur lors de la recherche sur le LDAP.";
             } else {
                 // Dès que la recherche renvoit une entrée, on stocke les attributs qui nous intéresse
-                res.on('searchEntry', entry => {
-                    // Cas un seul attribut où le résultat est une liste directement
-                    vals.push(entry.object[attribute]);
-                });
+                res.on('searchEntry', entry => { handler(entry); });
                 // Si la recherche renvoie une erreur, on renvoit
                 res.on('error', resErr => { throw resErr; });
-                // Si la recherche est finie on se déconnecte
-                res.on('end', _ => { LDAP.unbind(); });
+                // Quand la recherche est finie on se déconnecte
+                res.on('end', _ => { Basics.unbind(); });
             }
         });
-        // On renvoit le résultat
+    }
+    
+    /**
+     * @memberof LDAP
+     * @summary Fonction qui interroge le LDAP selon un protocole spécifié en argument et renvoit une liste de valeurs trouvées.
+     * @desc Cette fonction utilise {@link LDAP.search} directement.
+     * @arg {'gr'|'us'} domain - Emplacement de la requête (groupe ou utilisateur)
+     * @arg {string} attribute - Attribut unique à renvoyer
+     * @arg {string} id [null] - Identifiant facultatif pour une recherche triviale en o(1)
+     * @arg {string} filter ["(objectClass=*)"] - Filtre logique de la recherche (format [`RFC2254`](https://tools.ietf.org/search/rfc2254)) déjà passé au ldapEscape
+     * @return {Promise(string[])} Résultats de la recherche ; soit une liste de valeurs d'attributs, 
+     * soit une liste de dictionnaires si on veut plus d'un attribut (les clés du dictionnaire sont celles du LDAP)
+     * @static
+     * @async
+     */
+    static async searchSingle(domain: 'gr'|'us', attribute: string, id: string=null, filter: string="(objectClass=*)") : Promise<string[]> {
+        let vals=[];
+        Basics.search(domain, [attribute], id, filter,  entry => {
+            // Cas un seul attribut où le résultat est une liste directement
+            vals.push(entry.object[attribute]);
+        });
         return vals;
     }
     
     /**
+     * @memberof LDAP
      * @summary Fonction qui interroge le LDAP selon un protocole spécifié en argument et renvoit les valeurs trouvées.
      * @desc Cette fonction utilise ldapjs (voir [`Client API`](http://ldapjs.org/client.html) méthode search). Cette fonction fait une demande au LDAP
      * qu'elle filtre selon un schéma prédéfini dans `filter` et à chaque résultat (event SearchEntry) le met dans une liste, et renvoit la liste à l'issue (event end).
@@ -135,42 +161,20 @@ export class LDAP {
      * @async
      */
     static async searchMultiple(domain: 'gr'|'us', attributes: string[], id: string=null, filter: string="(objectClass=*)") : Promise<Array<dic>> {
-        LDAP.adminBind();
-        let dn ="";
-        if (id != null)     { dn+=ldapConfig.key_id+'='+id+','; }
-        if (domain == "gr") { dn+=ldapConfig.dn_groups; }
-        else                { dn+=ldapConfig.dn_users; }
         let vals=[];
-        // Interrogation LDAP selon filter
-        client.search(ldapEscape.dn("${txt}", { txt: dn}), {
-            "scope": "sub",
-            "filter": ldapEscape.filter("${txt}", { txt: filter}),
-            "attributes": attributes
-        }, (err, res) => {
-            // Gestion erreur ; pb car pas simple true / autre en sortie
-            if (err) {
-                throw "Erreur lors de la recherche sur le LDAP.";
-            } else {
-                // Dès que la recherche renvoit une entrée, on stocke les attributs qui nous intéresse
-                res.on('searchEntry', entry => {
-                    // Cas plusieurs attributs donc résultat dictionnaire
-                    vals.push({});
-                    attributes.forEach(attribute => {
-                        vals.slice(-1)[0][attribute]=entry.object[attribute];
-                    });
-                });
-                // Si la recherche renvoie une erreur, on renvoit
-                res.on('error', resErr => { throw resErr; });
-                // Si la recherche est finie on se déconnecte
-                res.on('end', _ => { LDAP.unbind(); });
-            }
+        Basics.search(domain, attributes, id, filter,  entry => {
+            // Cas plusieurs attributs donc résultat dictionnaire
+            vals.push({});
+            attributes.forEach(attribute => {
+                vals.slice(-1)[0][attribute]=entry.object[attribute];
+            });
         });
-        // On renvoit le résultat
         return vals;
     }
 
     //TBT
     /**
+     * @memberof LDAP
      * @summary Fonction qui permet de modifier un élément sur le LDAP. Gestion intelligente de l'appartenance à un binet.
      * @desc Cette fonction traite la demande avec ldapjs (voir [`Client API`](http://ldapjs.org/client.html) méthode modify).
      * @arg {'gr'|'us'} domain - Emplacement de la requête (groupe ou utilisateur)
@@ -184,7 +188,7 @@ export class LDAP {
      * @async
      */
     static async change(domain: 'gr'|'us', id: string, op: "add"|"del"|"replace", mod: dic) : Promise<boolean> {
-        LDAP.adminBind();
+        Basics.adminBind();
         let dn = ldapConfig.key_id+'='+id+','
         if (domain == "gr") { dn+=ldapConfig.dn_groups }
         else                { dn+=ldapConfig.dn_users }
@@ -196,12 +200,13 @@ export class LDAP {
         }), err => {
             throw "Erreur lors d'une opération de modification sur le LDAP.";
         });
-        LDAP.unbind();
+        Basics.unbind();
         return true;
     }
 
     //TBT
     /**
+     * @memberof LDAP
      * @summary Fonction qui permet de rajouter un élément sur le LDAP.
      * @desc  Cette fonction traite la demande avec ldapjs (voir [`Client API`](http://ldapjs.org/client.html) méthode add).
      * @arg {'gr'|'us'} domain - Emplacement de la requête (groupe ou utilisateur)
@@ -212,7 +217,7 @@ export class LDAP {
      * @async
      */
     static async add(domain: 'gr'|'us', vals) : Promise<boolean> {
-        LDAP.adminBind();
+        Basics.adminBind();
         let dn = ldapConfig.key_id+"="+vals[ldapConfig.key_id];
         if (domain == "gr") { dn+=ldapConfig.dn_groups; }
         else                { dn+=ldapConfig.dn_users; }
@@ -220,12 +225,13 @@ export class LDAP {
         client.add(ldapEscape.dn("${txt}", { txt: dn}), vals, err => {
             throw "Erreur lors d'une opération d'ajout sur le LDAP.";
         });
-        LDAP.unbind();
+        Basics.unbind();
         return true;
     }
 
     //TBT
     /**
+     * @memberof LDAP
      * @summary Fonction qui permet de supprimer une feuille du LDAP.
      * @desc Cette fonction traite la demande avec ldapjs (voir [`Client API`](http://ldapjs.org/client.html) méthode del).
      * Elle est différente de modify avec "del" car elle affecte directement une feuille et pas un attribut.
@@ -236,7 +242,7 @@ export class LDAP {
      * @async
      */
     static async clear(domain: 'gr'|'us', id: string) : Promise<boolean> {
-        LDAP.adminBind();
+        Basics.adminBind();
         let dn = ldapConfig.key_id+'='+id+','
         if (domain == "gr") { dn+=ldapConfig.dn_groups; }
         else                { dn+=ldapConfig.dn_users; }
@@ -244,7 +250,7 @@ export class LDAP {
         client.del(ldapEscape.dn("${txt}", {txt: dn}), err => {
             throw "Erreur lors d'une opération de suppression sur le LDAP.";
         });
-        LDAP.unbind();
+        Basics.unbind();
         return true;
     }
 }
\ No newline at end of file
diff --git a/src/ldap/internal/config.ts b/src/ldap/internal/config.ts
index 473abac4c305bf4b31612f0d56b7f6f4ce8b08cd..0bf07a73926b0f64852382a4037dadc493eaa012 100644
--- a/src/ldap/internal/config.ts
+++ b/src/ldap/internal/config.ts
@@ -1,5 +1,11 @@
+/**
+ * Namespace qui regroupe toutes les fonctions en rapport avec le LDAP - API et fonctions internes
+ * @namespace LDAP
+ */
+
 /**
  * @file Importe la configuration du LDAP au sein de l'application, et remplace certaines valeurs en fonction des variables d'environnement.
+ * @memberof LDAP
  * @author manifold
  */
 
@@ -16,4 +22,8 @@ export const credentialsLdapConfig = JSON.parse(fs.readFileSync(path_credentials
 // Override config server from environment
 if (process.env.LDAP_URI != null) {
     ldapConfig.server = process.env.LDAP_URI;
+}
+else {
+    if (process.env.TARGET_ENV =`production`)   { ldapConfig.server = ldapConfig.server_prod; }
+    else                                        { ldapConfig.server = ldapConfig.server_dev; }
 }
\ No newline at end of file
diff --git a/src/ldap/internal/utilities.ts b/src/ldap/internal/tools.ts
similarity index 92%
rename from src/ldap/internal/utilities.ts
rename to src/ldap/internal/tools.ts
index f4b9613cde1dee830097724f6f7a749af1b801e1..cb7912224c14f5fd13278897ed54052103dc7242 100644
--- a/src/ldap/internal/utilities.ts
+++ b/src/ldap/internal/tools.ts
@@ -1,11 +1,10 @@
 /**
- * @file Ce fichier regroupe les fonctions simples de recherche et de test utiles, mais trop puissantes pour être exportées directement.
- * Le découpage par fichier est arbitraire mais permet de regrouper certaines classes proches.
+ * @file Ce fichier regroupe les fonctions génériques de recherche et de test utiles, mais trop puissantes pour être exportées directement.
  * @author hawkspar
  */
 
 import {ldapConfig} from './config';
-import {LDAP} from './basics';
+import {Basics} from './basics';
 import {userData} from '../export/user';
 import {groupData} from '../export/group';
 
@@ -15,13 +14,15 @@ import {groupData} from '../export/group';
 
 export class Tools {
     /**
-     * @class Cette classe contient des fonctions intermédiaires qui ne sont pas destinées à être utilisées dans les resolvers.
+     * @memberof LDAP
+     * @class Tools
+     * @classdesc Cette classe contient des fonctions intermédiaires qui ne sont pas destinées à être utilisées dans les resolvers.
      * @summary Constructeur vide.
-     * @author hawkspar
-    */
+     */
     constructor() {}
      
     /**
+     * @memberof LDAP
      * @summary Fonction qui renvoit toutes les infos relatives à un groupe ou un utilisateur particulier.
      * @desc Cette fonction utilise {@link LDAP.search} avec des attributs prédéfinis.
      * @param T - Format renvoyé (en pratique {@link userData} ou {@link groupData})
@@ -39,7 +40,7 @@ export class Tools {
             var dirtyKeys = ldapConfig.user;
         }
         let cleanData : T;
-        let dirtyData = await LDAP.searchMultiple(domain, dirtyKeys.values(), id)[0];
+        let dirtyData = await Basics.searchMultiple(domain, dirtyKeys.values(), id)[0];
         // Rename output
         for (let uncleanKey in dirtyData) {
             for (let cleanKey in cleanData) {
@@ -51,6 +52,7 @@ export class Tools {
 
     
     /**
+     * @memberof LDAP
      * @summary Fonction qui retrouve les id des paxs ou groupes validant les critères de recherche. Etape vers vrai TOL (Trombino On Line).
      * Utiliser {@link peekUser} au cas par cas après pour obtenir les vraies infos.
      * @desc Cette fonction utilise {@link LDAP.search} mais avec un filtre généré à la volée. Accepte des champs exacts ou incomplets pour la plupart des champs
@@ -85,10 +87,11 @@ export class Tools {
             }
         }
         // Appel avec filtre de l'espace 
-        return LDAP.searchSingle(domain, ldapConfig.key_id, null, filter);
+        return Basics.searchSingle(domain, ldapConfig.key_id, null, filter);
     }
     
     /**
+     * @memberof LDAP
      * @summary Fonction qui édite un groupe ou utilisateur existant dans le LDAP. N'agit pas sur l'apprtenance à un groupe.
      * @desc Appelle {@link LDAP.change}.
      * @arg {"us"|"gr"} domain - Domaine de l'opération' (utilisateur ou groupe).
@@ -114,7 +117,7 @@ export class Tools {
                 dirtyData[dirtyKeys.key]=data[key];
             }
         });
-        return LDAP.change(domain,id,"replace",dirtyData);
+        return Basics.change(domain,id,"replace",dirtyData);
     }
 
     /**
@@ -124,6 +127,7 @@ export class Tools {
      * @return {string} Nouveau id
      */
     /**
+     * @memberof LDAP
      * @summary Cette fonction teste une valeur d'un attribut (typiquement un identifiant) et le fait évoluer jusqu'à ce qu'il soit unique.
      * @desc Librement adapté de Stack Overflow. Appelle {@link LDAP.search} pour vérifier 
      * qu'il n'y a pas d'autres occurences de cette valeur pour cette attribut
@@ -141,7 +145,7 @@ export class Tools {
     static async ensureUnique(value: string, attribute: string, domain: 'gr'|'us', changeValue: (string, number) => string, n: number=0) : Promise<string> {
         // Recherche d'autres occurences de l'id
         try {
-            return LDAP.searchSingle(domain, ldapConfig.key_id, null, "("+attribute+"="+value+")").then(function (matches: string[]) {
+            return Basics.searchSingle(domain, ldapConfig.key_id, null, "("+attribute+"="+value+")").then(function (matches: string[]) {
                 if (!matches) { throw ""; }
                 // On renvoit la valeur si elle est bien unique
                 else if (matches.length=0) { return value; }
@@ -155,6 +159,7 @@ export class Tools {
     }
 
     /**
+     * @memberof LDAP
      * @summary Cette fonction génère un uid standard, puis le fait évoluer jusqu'à ce qu'il soit unique.
      * @desc Limité à un appel à {@link Tools.ensureUnique} avec les bons paramètres, et quelques opérations sur l'uid pour qu'il soit valide (escape, normalisation).
      * @param {string} givenName - Prénom
@@ -180,6 +185,7 @@ export class Tools {
     }
 
     /**
+     * @memberof LDAP
      * @summary Cette fonction génère un id lisible, puis le fait évoluer jusqu'à ce qu'il soit unique.
      * @desc Limité à un appel à {@link Tools.ensureUnique} avec les bons paramètres, et quelques opérations sur l'uid pour qu'il soit valide (escape, normalisation).
      * @param {string} name - Nom
@@ -202,6 +208,7 @@ export class Tools {
     }
 
     /**
+     * @memberof LDAP
      * @summary Cette fonction teste une valeur dummy (0) pour un identifiant numérique puis le fait évoluer aléatoirement (entre 1 et 100 000) jusqu'à ce qu'il soit unique.
      * @param {string} attribut - Intitulé exact de l'id concerné
      * @param {"gr"|"us"} domain - Domaine dans lequel l'attribut doit être unique
@@ -219,6 +226,7 @@ export class Tools {
     }
 
     /**
+     * @memberof LDAP
      * @summary Fonction qui retrouve les groupes dont un individu est membre.
      * @desc Cette fonction utilise {@link LDAP.search} va directement à la feuille de l'utilisateur.
      * @arg {string} uid - Identifiant de l'individu à interroger (le plus souvent prenom.nom, parfois l'année, supposé valide)
@@ -228,7 +236,7 @@ export class Tools {
      */
     static async getGroups(uid: string) : Promise<string[]> {
         try {
-            return LDAP.searchSingle("us", ldapConfig.user.groups, uid);
+            return Basics.searchSingle("us", ldapConfig.user.groups, uid);
         }
         catch(err) {
             throw "Erreur lors de la recherche des groupes d'un individu.";
@@ -236,6 +244,7 @@ export class Tools {
     }
     
     /**
+     * @memberof LDAP
      * @summary Fonction qui retrouve la liste des membres d'un groupe.
      * @desc Cette fonction utilise {@link LDAP.search} avec un dictionnaire prédéfini dans ldapConfig.json.
      * @arg {string} gid - Identifiant du groupe à interroger (le plus souvent nom du groupe en minuscule)
@@ -245,7 +254,7 @@ export class Tools {
      */
     static async getMembers(gid: string) : Promise<string[]> {
         try {
-            return LDAP.searchSingle("gr", ldapConfig.group.members, gid);
+            return Basics.searchSingle("gr", ldapConfig.group.members, gid);
         }
         catch(err) {
             throw "Erreur lors de la recherche des membres d'un groupe.";
@@ -253,6 +262,7 @@ export class Tools {
     }
     
     /**
+     * @memberof LDAP
      * @summary Fonction qui retrouve la liste des admins d'un groupe.
      * @desc Cette fonction utilise {@link LDAP.search} avec un dictionnaire prédéfini dans ldapConfig.json.
      * @arg {string} gid - Identifiant du groupe à interroger (le plus souvent nom du groupe en minuscule)
@@ -262,7 +272,7 @@ export class Tools {
      */
     static async getAdmins(gid: string) : Promise<string[]> {
         try {
-            return LDAP.searchSingle("gr", ldapConfig.group.admins, gid);
+            return Basics.searchSingle("gr", ldapConfig.group.admins, gid);
         }
         catch(err) {
             throw "Erreur lors de la recherche des admins d'un groupe.";
@@ -270,6 +280,7 @@ export class Tools {
     }
 
     /**
+     * @memberof LDAP
      * @summary Cette fonction teste si un utilisateur est membre d'un groupe.
      * @desc Utilise les méthodes statiques {@link open.getGroups} et {@link open.getMembers}
      * @param {string} uid - Identifiant de l'utilisateur à tester 
@@ -293,6 +304,7 @@ export class Tools {
     }
 
     /**
+     * @memberof LDAP
      * @summary Cette fonction teste si un utilisateur est admin d'un groupe.
      * @desc Utilise la méthode statique {@link Open.getAdmins}
      * @param {string} uid - Identifiant de l'utilisateur à tester