diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c5c956f4b285c701b0cb02ecd4b4607a1fee55e1..d89c523accdb6e884c1fe8c5baa5b314d4b578f3 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -34,7 +34,7 @@ build:
       - ldap_connexion_config.json
       - build/
       - node_modules/
-    expire_in: 240   min
+    expire_in: 240 min
   tags:
     - database
     - build
@@ -49,10 +49,18 @@ test:lint:
 
 deploy_staging:
   stage: deploy
+  only:
+    - master
+  before_script:
+    - eval $(ssh-agent -s)
+    - ssh-add <(echo "$STAGING_PRIVATE_KEY")
+    - mkdir -p ~/.ssh
+    - echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
   script:
     - npm run build
-    - mkdir -p /opt/sigma-back-dev
-    - cp -r build/ /opt/sigma-back-dev/build/
+    - ssh -p22 sigma-dev@roued "mkdir -p /opt/sigma-back-dev"
+    - ssh -p22 sigma-dev@roued "rm -rf /opt/sigma-back-dev/build"
+    - scp -p22 -r build/ sigma-dev@roued:/opt/sigma-back-dev/build
   environment:
     name: staging
     url: http://129.104.210.10:3000
diff --git a/db/migrations/20180303192411_create_metaGroups.js b/db/migrations/20180303192411_create_metaGroups.js
new file mode 100644
index 0000000000000000000000000000000000000000..90df1a877c7fe944429a21ce190b856bb0ac3cfd
--- /dev/null
+++ b/db/migrations/20180303192411_create_metaGroups.js
@@ -0,0 +1,49 @@
+
+/* 
+Une mutation pour rajouter dans la BDD les types SimpleGroup et MetaGroup 
+(cf la documentation de l'interface GraphQL)
+Les objets qui étaient jusqu''à présent stoqués dans la table groups 
+sont déplacés dans la table simple_groups
+En cas de rollback, le déplacement se fait dans l'autre sens
+(et les meta groupes sont perdus)
+
+Après cette mutation, plus rien n'est sensé être mis directement dans la table groups
+*/
+
+exports.up = function(knex, Promise) {
+    return knex('groups').select().then( groups_content => {
+        return knex('groups').del().then(function () {
+            return knex.schema.table('groups', function (table){
+                table.dropColumn('school');
+                table.dropColumn('parentuid');
+            }).then(()=> {
+                return knex.schema.createTable('simple_groups', function (table){
+                    table.inherits('groups');
+                    table.string('parentuid');
+                    table.enum('school', ['polytechnique', 'ensta', 'supoptique']).notNullable();
+                }).then(() => {
+                    return knex.schema.createTable('meta_groups', function (table){
+                        table.inherits('groups');
+                    }).then(function(){
+                        return knex('simple_groups').insert(groups_content);
+                    });
+                });
+            });
+        });
+    });
+};
+
+exports.down = function(knex, Promise) {
+    return knex('simple_groups').select().then(simple_groups_content => {
+        return knex.schema.dropTable('simple_groups').then(function (){
+            return knex.schema.dropTable('meta_groups').then(function (){
+                return knex.schema.table('groups', function (table){
+                    table.string('parentuid');
+                    table.enum('school', ['polytechnique', 'ensta', 'supoptique']).notNullable();
+                }).then(function (){
+                    return knex('groups').insert(simple_groups_content);
+                });
+            });
+        });
+    });
+};
diff --git a/db/migrations/20180304154225_group_type_column.js b/db/migrations/20180304154225_group_type_column.js
new file mode 100644
index 0000000000000000000000000000000000000000..f178a0a9ddf63ec1de5e2e6e050eb5ab4ea6af1c
--- /dev/null
+++ b/db/migrations/20180304154225_group_type_column.js
@@ -0,0 +1,17 @@
+
+exports.up = function(knex, Promise) {
+    return knex.schema.table('groups', function(table) {
+        table.enum('type', ['simple', 'meta', 'error']).notNullable().defaultTo('error');
+    }).then( () => {
+        return knex('simple_groups').update({type : "simple"}).then(() => {
+            return knex('meta_groups').update({type : "meta"});
+        });
+    });
+  
+};
+
+exports.down = function(knex, Promise) {
+    return knex.schema.table('groups', function(table) {
+        table.dropColumn('type');
+    });
+};
diff --git a/db/seeds/01_create_groups.js b/db/seeds/01_create_groups.js
index 1eb823722ccc15ba7e2b75ae5dda990b632c4a71..ee9c1ce9463b9c3d697978667f06c15da9e955b1 100644
--- a/db/seeds/01_create_groups.js
+++ b/db/seeds/01_create_groups.js
@@ -3,44 +3,61 @@ exports.seed = function(knex, Promise) {
   // Deletes ALL existing entries
   return knex('groups').del()
     .then(function () {
+    knex('simple_groups').del()
+    .then(function() {
       // Inserts seed entries
-      const groups = [{
+      const simple_groups = [{
           name: 'BR',
           uid: 'br',
           website: 'br.binets.fr',
           description: 'Le Binet Réseau est responsable du réseau internet des élèves sur le campus de l\'Ecole polytechnique.',
           school: 'polytechnique',
-          parentuid: 'kes'
+          parentuid: 'kes',
+          type : 'simple'
         },{
           name: 'JTX',
           uid: 'jtx',
           website: 'binet-jtx.com',
           school: 'polytechnique',
-          parentuid: 'kes'
+          parentuid: 'kes',
+          type : 'simple'
         },{
           name: 'Kès',
           uid: 'kes',
           website: 'kes.binets.fr',
-          school: 'polytechnique'
+          school: 'polytechnique',
+          type : 'simple'
         },{
           name: 'DaTA',
           uid: 'data',
           website: 'data-ensta.fr',
           school: 'ensta',
-          parentuid: 'bdeensta'
+          parentuid: 'bdeensta',
+          type : 'simple'
         },{
           name: 'Laser Wave',
           uid: 'laserwave',
           website: 'laserwave.fr',
-          school: 'supoptique'
+          school: 'supoptique',
+          type : 'simple'
         },{
           name: 'BDE Ensta',
           uid: 'bdeensta',
           website: 'http://bde.ensta-paristech.fr/',
-          school: 'ensta'
-        }
+          school: 'ensta',
+          type : 'simple'
+        },
+        {
+          name: 'Subaïsse',
+          uid: 'subaisse',
+          description: 'Le Binet de ceux qui subissent',
+          school: 'polytechnique',
+          parentuid: 'kes',
+          type : 'simple'
+      },
       ];
 
-      return knex('groups').insert(groups);
+      return knex('simple_groups').insert(simple_groups);
     });
+  });
 };
diff --git a/db/seeds/03_make_requests.js b/db/seeds/03_make_requests.js
index 2cb07fa44bcd80687b11bacb6099acb4d5c2b87e..aceaf4721893cb157cd6d5197384e49ff99b0e36 100644
--- a/db/seeds/03_make_requests.js
+++ b/db/seeds/03_make_requests.js
@@ -2,19 +2,37 @@
 exports.seed = function(knex, Promise) {
   // Deletes ALL existing entries
   return knex('user_join_group').del()
-    .then(function () {
-      // Inserts seed entries
-      return knex('user_join_group').insert([
-        { id: 1, 
-          recipient: 'br',
-          message: "C'est ici pour développer sigma ?",
-          useruid: "anatole.romon"
-        },
-        { id: 2, 
-          recipient: 'br',
-          message: "Bonjour, je cherche le binet subaisse",
-          useruid: "quentin.gendre"
-        }
-      ]);
-    });
+  .then(function () {
+    // Inserts seed entries
+  return knex('user_join_group').insert([
+    { id: 1, 
+      recipient: 'br',
+      message: "C'est ici pour développer sigma ?",
+      useruid: "anatole.romon"
+    },
+    { id: 2, 
+      recipient: 'br',
+      message: "Bonjour, je cherche le binet subaisse",
+      useruid: "quentin.gendre"
+    },
+    {id : 3,
+    recipient: 'jtx',
+    message: "Quand je serais grand je serais cinéaste !",
+    useruid: "anatole.romon"
+  }
+  ]).then(() => {
+  return knex('group_join_event').del()
+  .then(function (){
+  return knex('group_join_event').insert([
+    {
+      id : 4,
+      recipient : "br",
+      message : "nous aussi on veut coder sigma",
+      eventuid : 42,
+      senderuid : "subaisse"
+    }
+  ]);
+  });
+  });
+  });
 };
diff --git a/db/seeds/04_make_metagroups.js b/db/seeds/04_make_metagroups.js
new file mode 100644
index 0000000000000000000000000000000000000000..432bb33d1b96b6f4fda099d16cbf35d471193c6a
--- /dev/null
+++ b/db/seeds/04_make_metagroups.js
@@ -0,0 +1,24 @@
+
+exports.seed = function(knex, Promise) {
+    // Deletes ALL existing entries
+    return knex('meta_groups').del()
+      .then(function () {
+        // Inserts seed entries
+        return knex('meta_groups').insert([
+          { 
+            name: 'Fédérez',
+            uid: 'federez',
+            website: 'federez.io',
+            description: "L'association de toutes les associations de réseau des écoles",
+            type : 'meta'
+          },
+          { 
+            name: 'BSCkBl',
+            uid: 'bsckbl',
+            website: 'bsckbl.binets.fr',
+            type : 'meta'
+          }
+        ]);
+      });
+  };
+  
\ No newline at end of file
diff --git a/package.json b/package.json
index cd95995964c78a2258e982a934fd227fbba57a7e..3fb5e2449494c39592716faed3543c5ace252152 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,7 @@
     "knex": "^0.14.4",
     "ldap-escape": "^1.1.5",
     "ldapjs": "^1.0.2",
+    "lodash": "^4.17.5",
     "morgan": "^1.9.0",
     "passport": "^0.4.0",
     "passport-ldapauth": "^2.0.0",
diff --git a/src/graphql/connectors/connectors.js b/src/graphql/connectors/connectors.js
new file mode 100644
index 0000000000000000000000000000000000000000..0aea999c8b86c9b16380d9ecc67a98c28dbe84b5
--- /dev/null
+++ b/src/graphql/connectors/connectors.js
@@ -0,0 +1,378 @@
+/**
+ * @file Fonctions pour interagir avec la BDD sigma et le LDAP.
+ * @author akka vodol
+ */
+import knex from '../../../db/knex_router';
+import { renseignerSurUtilisateur, repliquerTOLdesIds, 
+    listerGroupes, listerMembres, listerAdministrateurs 
+} from '../../ldap/ldap_data';
+import { exportAllDeclaration } from 'babel-types';
+
+export { renseignerSurUtilisateur, repliquerTOLdesIds, listerMembres };
+
+/**
+ * @summary Génère une promise.
+ * @function
+ * @desc Les fonctions ici sont toutes supposées renvoyer une promise. 
+ * Si on veut renvoyer une valeur directement, cette fonction permet de construire 
+ * une Promise qui renvoie cette valeur facilement.
+ * @arg {Object} val - La valeur qu'on veut renvoyer.
+ * @return {Promise(Object)} Une promise qui renvoi val
+ */
+const quickPromise = (val) => {
+    return new Promise( (resolve, reject) => {
+        resolve(val);
+    });
+};
+
+/**
+ * @summary Renvoie le type d'un groupe.
+ * @function
+ * @desc Parcours les BDD pour savoir dans laquelle se trouve le groupe ayant l'UID donné. 
+ * Cette opération nécéssite un parcours de base de donnée, et il est préférable de ne pas 
+ * sans servir si on a un autre moyend de connaitre le typed d'un groupe
+ * (Par exemple, si on dispose d'un retour de BDD pour ce groupe. Le champ 'type' indique alors son type.)
+ * @arg {Object} user - Objet contenant un attribut `uid` de type `string`. 
+ * User représente l'utilisateur qui a effectué la requête. 
+ * @arg {Object} groupUID - L'id du groupe dont on veut connaître le type.
+ * @return {Promise(String)} Un string représentant le type du groupe.
+ * Peut être "SimpleGroup" ou "MetaGroup". Renvoie `Undefined` si le groupe n'existe pas
+ */
+export const getGroupType = (user, groupUID) => {
+    return knex('simple_groups').select('uid').where('uid', groupUID).then( sg_res => {
+        if(sg_res)
+            return "SimpleGroup";
+        return knex('meta_groups').select('uid').where('uid', groupUID).then(mg_res => {
+            if(mg_res)
+                return "MetaGroup";
+            return undefined;
+        });
+    });
+};
+
+/**
+ * @summary Renvoie tous les utilisateurs ayant des droits d'administrateur sur un groupe.
+ * @function
+ * @desc Les utilisateurs qui ont un droit d'administrateur sur un groupe simple sont ses administrateurs 
+ * et les utilisateurs ayant droit d'admin sur son parent.
+ * Les utilisateurs ayant droit d'admin sur un meta-groupe sont les utilisateurs 
+ * ayant droit d'admin sur un des groupes membres
+ * @arg {String} uid - L'uid du groupe dont on veut les administrateurs. 
+ * @return {Promise} Retour de requête knex. Promise qui renvera une liste 
+ * de tous les utilisateurs ayant droit d'admin sur le groupe
+ */
+export const getUsersWithAdminRights = (user, groupUID) => {
+    return getGroupType(user, groupUID).then( groupType => {
+        
+        if(groupType == "SimpleGroup"){
+            return listerAdministrateurs(user, groupUID).then(adminList => {
+                if (typeof adminList == "undefined")
+                    return undefined;
+                else
+                    return knex('simple_groups').select('parentuid').where('uid', groupUID).then(req => {
+                        if (req[0].parentuid)
+                            return getUsersWithAdminRights(user, req[0].parentuid).then(parentAdmins => {
+                                return adminList.concat(parentAdmins);
+                            });
+                        else
+                            // pour les besoins des tests, anatole romon a tout les droits
+                            return adminList.concat(['anatole.romon']); 
+                    });
+            });
+        }else{
+            return getMetaGroupAdminMembers(user, groupUID).then(mg_members => {
+                function fuse (l){
+                    if(l)
+                        return getUsersWithAdminRights(l.pop()).then(usrs => fuse(l).concat(usrs) );
+                    else
+                        return [];
+                }
+            });
+        }
+    });
+};
+
+/**
+ * @summary teste si un utilisateur a des droits
+ * @desc Cette fonction effectue une requête knex. Elle gère l'arête de parenté.
+ * @arg {Object} user - Objet contenant un attribut `uid` de type `string`. 
+ * User représente l'utilisateur qui a effectué la requête. 
+ * @return {Promise} Retour de requête knex. Liste de tous les groupes que l'utilisateur a le droit de voire.
+ */
+export const hasAdminRights = (user, groupUID) => {
+    if(user.uid == "anatole.romon")
+        return quickPromise(true);
+    return getUsersWithAdminRights(user, groupUID).then(adminList => {
+        return (typeof adminList != "undefined" && adminList.indexOf(user.uid) != -1);
+    });
+};
+
+
+/**
+ * @summary Renvoie une liste des id de tous les groupes visibles par l'utilisateur
+ * @desc Cette fonction génère un callback qui créé une table contenant les uid de tous les groupes visibles
+ * @arg {Object} user - Objet contenant un attribut `uid` de type `string`. 
+ * User représente l'utilisateur qui a effectué la requête. 
+ * @return {Promise(Callback)} callback contruisant une requête knex pour une table de tous les id visibles.
+ */
+export const getVisibleGroupCallback = (user) => {
+    return listerGroupes(user, user.uid).then(group_ids => {
+        return function (global_query_builder){
+            if (typeof group_ids == "undefined")
+                throw "invalid user";
+            var membered_groups = qb => qb.select('simple_groups.uid').from('simple_groups').whereIn('uid', group_ids.concat(['kes']));
+            var directly_visible_simple_groups = qb =>  qb.with('membered_groups', membered_groups).select('simple_groups.uid').from('simple_groups').distinct()
+                .innerJoin('membered_groups',
+                    function () {
+                        this.on('simple_groups.uid', '=', 'membered_groups.uid')
+                            .orOn('simple_groups.parentuid', '=', 'membered_groups.uid');
+                    }
+                );
+            return directly_visible_simple_groups(global_query_builder);
+        };
+    });
+    
+};
+
+/**
+ * @summary Renvoie le nom de la table dans laquelle il faut chercher en fonction de ce qu'on veut
+ * @desc a remplir
+ * @arg {String} wantedType - Un string indiquant le type de groupe qu'on veut. Peut être `"simple"`, `"meta"` ou `"all"`. 
+ * @return {String} Le nom de la table dans laquelle la requète doit être effectuée.
+ */
+function getGroupTableName(wantedType){
+    switch(wantedType){
+    case "simple":
+        return "simple_groups";
+    case "SimpleGroup":
+        return "simple_groups";
+    case "meta":
+        return "meta_groups";
+    case "MetaGroup":
+        return "meta_groups";
+    case "all":
+        return "groups";
+    default:
+        throw "invalid type request : " + wantedType + "is not a valid group type";
+    }
+}
+
+/**
+ * @summary Renvoie un unique groupe, ssi ce groupe est visible par l'utilisateur
+ * @desc Pour l'instant, la fonction effectue la même requête que `getAllVisibleGroups` 
+ * et restreint au groupe demandé. Cette fonction peut être implémentée de manière 
+ * plus efficace et plus chiante.
+ * @arg {Object} user - Utilisateur effectuant la requête. 
+ * @arg {String} uid - Identifiant du groupe voulu.
+ * @arg {String} type - Type de groupe voulu. `"simple"`, `"meta"` ou `"all"`.
+ * @return {Promise(group)} Retour de requête knex. Le groupe demandé, si l'utilisateur a le droit de la voire.
+ */
+export async function getGroupIfVisible(user, groupUID, type="all"){
+    let group_table_name = getGroupTableName(type);
+    let visible_groups = await getVisibleGroupCallback(user);
+    return knex.with('visible_groups', visible_groups).select()
+        .from(group_table_name).innerJoin('visible_groups', function (){
+            this.on('visible_groups.uid', '=', group_table_name + '.uid');
+        }).where(group_table_name + '.uid', groupUID).then(res => res[0]);
+};
+
+export const getSimpleGroupIfVisible = (user, groupUID) => getGroupIfVisible(user, groupUID, "simple");
+export const getMetaGroupIfVisible = (user, groupUID) => getGroupIfVisible(user, groupUID, "meta");
+
+/**
+ * @summary Renvoie tous les groupes visibles par l'utilisateur user
+ * @desc Cette fonction effectue une requête knex. Elle gère l'arête de parenté.
+ * @arg {Object} user - Représente l'utilisateur qui a effectué la requête. 
+ * @arg {String} wantedType - Type de groupe voulu : `"simple"`, `"meta"` ou `"all"`. 
+ * @return {Promise} Retour de requête knex. Liste de tous les groupes que l'utilisateur a le droit de voire.
+ */
+export async function getAllVisibleGroups(user, wantedType="all"){
+    let group_table_name = getGroupTableName(wantedType);
+    let visible_groups = await getVisibleGroupCallback(user);
+    return knex.with('visible_groups', visible_groups).select().from(group_table_name).innerJoin('visible_groups', function (){
+        this.on('visible_groups.uid', '=', group_table_name + '.uid');
+    });
+};
+
+export const getAllVisibleSimpleGroups = (user) => getAllVisibleGroups(user,"simple");
+export const getAllVisibleMetaGroups = (user) => getAllVisibleGroups(user,"meta");
+
+/**
+ * @summary Teste si un utilisateur est membre d'un groupe
+ * @arg {Object} user - Représente l'utilisateur qui a effectué la requête. 
+ * @arg {Object} groupUID - L'id du groupe dont on veu savoir si l'utilisateur est membre. 
+ * @return {Promise(Boolean)} Boolean indiquant si l'utilisateur est membre du groupe.
+ */
+export const isMember = (user, groupUID) => {
+    return listerGroupes(user, user.uid).then(group_ids => group_ids && group_ids.indexOf(groupUID) != -1);
+};
+
+/**
+ * @summary Attribue un UID qui n'a pas encore été utilisé à un groupe
+ * @desc RASifie le string initialUID si necessaire (ramené à de l'ASCCI sans espace), puis si l'uid est deja pris rajoute un n a la fin et reteste
+ * @arg {String} uid - L'uid du groupe dont on veut les administrateurs. 
+ * @return {Promise} Retour de requête knex. Promise qui renvera une liste de tous les utilisateurs ayant droit d'admin sur le groupe
+ */
+export function getAvailablegroupUID(initialUID){
+    let rasUID = initialUID.replace(' ', '_').replace(/\W/g, '').toLowerCase();
+    return knex.from('groups').where('uid', rasUID).then(res => {
+        if (res.length == 0) {
+            return (rasUID);
+        } else {
+            return (getAvailablegroupUID(rasUID + 'n'));
+        }
+    });
+};
+
+/**
+ * @summary Créé un groupe si les arguments sont tous valides
+ * @desc Les arguments doivent être valides, sauf pour uid. Une clé uid valide sera générée dans tous les cas. 
+ * Les authorisations de l'utilisateur ne sont pas vérifiées
+ * On teste si l'utilisateur qui envoie la requête a des droits d'admin sur le parent du groupe qui doit être créé, avec la fonction
+ * `getUsersWithAdminRights`.
+ * Si un argument est invalide ou si l'utilisateur n'a pas les droits, la fonction renvoie une erreur
+ * @arg {Object} user - L'utilisateur qui effectue la requête. 
+ * @arg {Object} args - Les arguments envoyés à la mutation. Cf le schéma GraphQL 
+ * @return {Promise} Retour de requête knex. Le groupe qui vient d'être créé. En cas d'echec, renvoie une erreur.
+ */
+export async function createSubgroup(user, args){
+    if (typeof args.parentuid != 'string')
+        throw "Illegal argument : parentuid must be a non null string";
+    if (typeof args.name != 'string')
+        throw "Illegal argument : name must be a non null string";
+
+    let rasUID = await getAvailablegroupUID(args.uid);
+
+    // TODO : appeller une fonction de ldap_data pour y créer un groupe.
+    await knex('simple_groups').insert({
+        uid: rasUID,
+        parentuid: args.parentuid,
+        createdAt: knex.fn.now(),
+        updatedAt: this.createdAt,
+        name: args.name,
+        website: args.website,
+        description: args.description,
+        school: args.school,
+        type : "simple"
+    });
+
+    return getGroupIfVisible(user, rasUID);
+};
+
+/**
+ * @summary Créé un groupe si les arguments sont tous valides et l'utilisateur est authorisé
+ * @desc Les arguments doivent être valides, sauf pour uid. Une clé uid valide sera générée dans tous les cas. 
+ * On teste si l'utilisateur qui envoie la requête a des droits d'admin sur le parent du groupe qui doit être créé, avec la fonction `getUsersWithAdminRights`
+ * Si un argument est invalide ou si l'utilisateur n'a pas les droits, la fonction renvoie une erreur
+ * @arg {Object} user - L'utilisateur qui effectue la requête. 
+ * @arg {Object} args - Les arguments envoyés à la mutation. Cf le schéma GraphQL 
+ * @return {Promise} Retour de requête knex. Le groupe qui vient d'être créé. En cas d'echec, renvoie une erreur.
+ */
+export async function createGroupIfLegal(user, args){
+    if( await hasAdminRights(user, args.parentuid) ){
+        return createSubgroup(user, args);
+    }else{
+        throw "illegal request : you must have admin rights over a group to create a subgroup of that group";
+    }
+};
+
+/**
+ * @summary Renvoie toues les requêtes de type UserJoinGroup 
+ * @desc Une requête UserJoinGroup est envoyée par un utilisateur à un groupe, 
+ * pour demander à rejoindre ce groupe
+ * @arg {Object} user - L'utilisateur qui effectue la requête. 
+ * @arg {String} args - L'identifiant du groupe qui reçoit la requête. 
+ * @return {Promise(Object)} Retour de requête knex. Toutes les requêtes destinées au groupe.
+ */
+export function getUserJoinGroupRequests(user, recipientUID){
+    return knex.select('id', 'useruid', 'message').from('user_join_group')
+        .where('recipient', recipientUID);
+};
+
+/**
+ * @summary Renvoie toues les requêtes de type GroupJoinEvent 
+ * @desc Une requête UserJoinGroup est envoyée par un groupe à un évènement (donc aux administrateurs de l'évènement), 
+ * pour demander à rejoindre cet évènement.
+ * Remarque : toutes les requêtes ont pour le moment un attribut recipient, 
+ * mais ici il ne sera a terme pas utilisé.
+ * @arg {Object} user - L'utilisateur qui effectue la requête. 
+ * @arg {String} args - L'identifiant du groupe qui reçoit la requête. 
+ * @return {Promise(Object)} Retour de requête knex. Toutes les requêtes destinées au groupe.
+ */
+export function getGroupJoinEventRequests(user, recipientUID){
+    return knex.select('id', 'senderuid', 'eventuid', 'message').from('group_join_event')
+        .where('recipient', recipientUID);
+};
+
+
+/**
+ * @summary Renvoie toues les requêtes de type GroupJoinEvent 
+ * @desc Une requête UserJoinGroup est envoyée par un groupe à un évènement (donc aux administrateurs de l'évènement), 
+ * pour demander à rejoindre cet évènement.
+ * Remarque : toutes les requêtes ont pour le moment un attribut recipient, 
+ * mais ici il ne sera a terme pas utilisé.
+ * @arg {Object} user - L'utilisateur qui effectue la requête. 
+ * @arg {String} args - L'identifiant du groupe qui reçoit la requête. 
+ * @return {Promise(Object)} Retour de requête knex. Toutes les requêtes destinées au groupe.
+ */
+export const getYourGroupHostEventRequests = (user, recipientUID) => {
+    return knex.select('id', 'senderuid', 'eventuid', 'message').from('your_group_host_event')
+        .where('recipient', recipientUID);
+};
+
+
+//Don't forget the argument user is the guy who makes the request, not the user we want
+export const getUser = (user, userUID) => { 
+    const refactorer = (data) => {
+        return {
+            uid: userUID,
+            lastName: data.sn,
+            givenName: data.givenName,
+            birthdate: data.brBirthdate,
+            groups: data.brMemberOf,
+            mail: data.mail,
+            phone: data.telephoneNumber,
+            room: data.brRoom
+        };
+    };
+
+    const result = renseignerSurUtilisateur(user, userUID).then(res => {
+        return refactorer(res[0]);
+    });
+
+    return result;
+};
+
+/**
+ * @function Renvoie un événement en fonction de son identifiant.
+ * @param {*} user - Utilisateur effectuant la requête.
+ * @param {*} eventID - Identifiant unique de l'événement.
+ */
+export const getEvent = (user, eventID) => {
+    return quickPromise(null);
+};
+
+/**
+ * @function Renvoie simplement un groupe en fonction de son identifiant.
+ * @param {Object} user - Utilisateur effectuant la requête.
+ * @param {String} groupUID - Identifiant unique du groupe.
+ * @author manifold 
+ */
+export const getGroup = (user, groupUID) => {
+    // Une sélection sur une table renvoie un tableau.
+    // Knex renvoie une promesse, qui se résout en le tableau sélectionné.
+    // On récupère son unique valeur, puisqu'on filtre sur l'identifiant unique.
+    return knex.select().from('groups').where('uid',groupUID).then(results => results [0]);
+};
+
+export const getSimpleGroup = (user, groupUID) => {
+    return knex.select().from('simple_groups').where('uid',groupUID).then(results => results [0]);
+};
+
+export const getMetaGroup = (user, groupUID) => {
+    return knex.select().from('meta_groups').where('uid',groupUID).then(results => results [0]);
+};
+
+export const getMetaGroupAdminMembers = (user, metaGroupUID) => {
+    return quickPromise([]);
+};
\ No newline at end of file
diff --git a/src/graphql/db_utils.js b/src/graphql/db_utils.js
deleted file mode 100644
index f9330dc1b8caf03ab84702effd9a207cbc4fb836..0000000000000000000000000000000000000000
--- a/src/graphql/db_utils.js
+++ /dev/null
@@ -1,212 +0,0 @@
-/**
- * @file Fonctions pour interagir avec la BDD sigma et le LDAP.
- * @author akka vodol
- */
-import knex from '../../db/knex_router';
-import { renseignerSurUtilisateur, repliquerTOLdesIds, listerGroupes, listerMembres, listerAdministrateurs } from '../ldap/ldap_data';
-import { exportAllDeclaration } from 'babel-types';
-
-export { renseignerSurUtilisateur, repliquerTOLdesIds, listerMembres };
-
-/**
- * @summary Renvoie tous les utilisateurs ayant des droits d'administrateur sur un groupe.
- * @function
- * @desc Les utilisateurs qui ont un droit d'administrateur sur un groupe sont ses administrateurs et les utilisateurs ayant droit d'admin sur son parent
- * @arg {String} uid - L'uid du groupe dont on veut les administrateurs. 
- * @return {Promise} Retour de requête knex. Promise qui renvera une liste de tous les utilisateurs ayant droit d'admin sur le groupe
- */
-export const getUsersWithAdminRights = (user, groupUID) => {
-    return listerAdministrateurs(user, groupUID).then(adminList => {
-        if (typeof adminList == "undefined")
-            return undefined;
-        else
-            return knex('groups').select('parentuid').where('uid', groupUID).then(req => {
-                if (req[0].parentuid)
-                    return getUsersWithAdminRights(user, req[0].parentuid).then(parentAdmins => {
-                        return adminList.concat(parentAdmins);
-                    });
-                else
-                    return adminList.concat(['anatole.romon']); // pour les besoins des tests, anatole romon a tout les droits
-            });
-    });
-};
-
-/**
- * @summary teste si un utilisateur a des droits
- * @desc Cette fonction effectue une requête knex. Elle gère l'arête de parenté.
- * @arg {Object} user - Objet contenant un attribut *uid* de type *string*. User représente l'utilisateur qui a effectué la requête. 
- * @return {Promise} Retour de requête knex. Liste de tous les groupes que l'utilisateur a le droit de voire.
- */
-export const hasAdminRights = (user, groupUID) => {
-    return getUsersWithAdminRights(user, groupUID).then(adminList => {
-        return (typeof adminList != "undefined" && adminList.indexOf(user.uid) != -1);
-    });
-};
-
-/**
- * @summary Renvoie tous les groupes visibles par l'utilisateur user
- * @desc Cette fonction effectue une requête knex. Elle gère l'arête de parenté.
- * @arg {Object} user - Objet contenant un attribut *uid* de type *string*. User représente l'utilisateur qui a effectué la requête. 
- * @return {Promise} Retour de requête knex. Liste de tous les groupes que l'utilisateur a le droit de voire.
- */
-export const getAllVisibleGroups = (user) => {
-
-    return listerGroupes(user, user.uid).then(group_ids => {
-        if (typeof group_ids == "undefined")
-            throw "invalid user";
-        var membered_groups = qb => qb.select().from('groups').whereIn('uid', group_ids.concat(['kes']));
-        /* membered_groups est un callback qui reçoit un argument qb représentant un objet de requête (un truc qui s'utilise comme knex())
-        *  et effectue dessus la requête pour obtenir une table de tous les groupes dont user est membre
-        *  with est ensuite utilisé pour donner à ce retour de requête l'alias 'membered_groups'.
-        *  Cette table peut ainsi être JOIN avec la table groups. La condition de Join est donnée selon une syntaxe recopiée depuis la Doc Knex
-        *  On récupère tous les groupes tels que le groupe est dans membered_groups ou le parent est dans membered_groups
-        */
-        return knex.with('membered_groups', membered_groups).distinct('groups.*').select().from('groups').innerJoin('membered_groups',
-            function () {
-                this.on('groups.uid', '=', 'membered_groups.uid').orOn('groups.parentuid', '=', 'membered_groups.uid');
-            }
-        );
-    });
-};
-
-
-/**
- * @summary Teste si un utilisateur est membre d'un groupe
- * @arg {Object} user - Objet contenant un attribut *uid* de type *string*. User représente l'utilisateur qui a effectué la requête. 
- * @arg {Object} groupUID - L'id du groupe dont on veu savoir si l'utilisateur est membre. 
- * @return {Promise(Boolean)} Boolean indiquant si l'utilisateur est membre du groupe.
- */
-export const isMember = (user, groupUID) => {
-    return listerGroupes(user, user.uid).then(group_ids => group_ids && group_ids.indexOf(groupUID) != -1);
-};
-
-/**
- * @summary Renvoie un unique groupe, ssi ce groupe est visible par l'utilisateur
- * @desc Actuellement, la fonction effectue la même requête que *getAllVisibleGroups* et restreint au groupe demandé. Cette fonction peut être implémentée de manière plus efficace et plus chiante.
- * @arg {Object} user - Objet contenant un attribut *uid* de type *string*. User représente l'utilisateur qui a effectué la requête. 
- * @arg {String} uid - uid du groupe que l'on veut voire. 
- * @return {Promise(group)} Retour de requête knex. Le groupe demandé, si l'utilisateur a le droit de la voire.
- */
-export const getGroupIfVisible = (user, groupUID) => {
-    return listerGroupes(user, user.uid).then(group_ids => {
-        if (typeof group_ids == "undefined")
-            throw "invalid user";
-        var membered_groups = qb => qb.select().from('groups').whereIn('uid', group_ids.concat(['kes']));
-        return knex.with('membered_groups', membered_groups).distinct('groups.*').select().from('groups').innerJoin('membered_groups',
-            function () {
-                this.on('groups.uid', '=', 'membered_groups.uid').orOn('groups.parentuid', '=', 'membered_groups.uid');
-            }
-        ).where('groups.uid', groupUID).then(res => {
-            return res[0];
-        });
-    });
-};
-
-/**
- * @summary Attribue un UID qui n'a pas encore été utilisé à un groupe
- * @desc RASifie le string initialUID si necessaire (ramené à de l'ASCCI sans espace), puis si l'uid est deja pris rajoute un n a la fin et reteste
- * @arg {String} uid - L'uid du groupe dont on veut les administrateurs. 
- * @return {Promise} Retour de requête knex. Promise qui renvera une liste de tous les utilisateurs ayant droit d'admin sur le groupe
- */
-export const getAvailablegroupUID = (initialUID) => {
-    let rasUID = initialUID.replace(' ', '_').replace(/\W/g, '').toLowerCase();
-    return knex.from('groups').where('uid', rasUID).then(res => {
-        if (res.length == 0) {
-            return (rasUID);
-        } else {
-            return (getAvailablegroupUID(rasUID + 'n'));
-        }
-    });
-};
-
-/**
- * @summary Créé un groupe si les arguments sont tous valides
- * @desc Les arguments doivent être valides, sauf pour uid. Une clé uid valide sera générée dans tous les cas. 
- * Les authorisations de l'utilisateur ne sont pas vérifiées
- * On teste si l'utilisateur qui envoie la requête a des droits d'admin sur le parent du groupe qui doit être créé, avec la fonction *getUsersWithAdminRights*
- * Si un argument est invalide ou si l'utilisateur n'a pas les droits, la fonction renvoie une erreur
- * @arg {Object} user - L'utilisateur qui effectue la requête. 
- * @arg {Object} args - Les arguments envoyés à la mutation. Cf le schéma GraphQL 
- * @return {Promise} Retour de requête knex. Le groupe qui vient d'être créé. En cas d'echec, renvoie une erreur.
- */
-export const createSubgroup = (user, args) => {
-    if (typeof args.parentuid != 'string')
-        throw "Illegal argument : parentuid must be a non null string";
-    if (typeof args.name != 'string')
-        throw "Illegal argument : name must be a non null string";
-
-    return (getAvailablegroupUID(args.uid).then(rasUID => {
-        // TODO : appeller une fonction de ldap_data pour y créer un groupe.
-        return knex('groups').insert({
-            uid: rasUID,
-            parentuid: args.parentuid,
-            createdAt: knex.fn.now(),
-            updatedAt: this.createdAt,
-            name: args.name,
-            website: args.website,
-            description: args.description,
-            school: args.school
-        }).then(res => {
-            return getGroupIfVisible(user, rasUID);
-        });
-    }));
-};
-
-/**
- * @summary Créé un groupe si les arguments sont tous valides et l'utilisateur est authorisé
- * @desc Les arguments doivent être valides, sauf pour uid. Une clé uid valide sera générée dans tous les cas. 
- * On teste si l'utilisateur qui envoie la requête a des droits d'admin sur le parent du groupe qui doit être créé, avec la fonction *getUsersWithAdminRights*
- * Si un argument est invalide ou si l'utilisateur n'a pas les droits, la fonction renvoie une erreur
- * @arg {Object} user - L'utilisateur qui effectue la requête. 
- * @arg {Object} args - Les arguments envoyés à la mutation. Cf le schéma GraphQL 
- * @return {Promise} Retour de requête knex. Le groupe qui vient d'être créé. En cas d'echec, renvoie une erreur.
- */
-export const createGroupIfLegal = (user, args) => {
-    return hasAdminRights(user, args.parentuid).then(answer => {
-        if (!answer)
-            throw "illegal request : you must have admin rights over a group to create a subgroup of that group";
-        return createSubgroup(user, args);
-    });
-};
-
-export const getUserJoinGroupRequests = (user, recipientUID) => {
-    return knex('user_join_group').select(/*'id', 'useruid', 'message'*/)/*.where('recipient', recipientUID)*/;
-};
-
-//Don't forget the argument user is the guy who makes the request, not the user we want
-export const getUser = (user, userUID) => { 
-    return new Promise( (resolve, reject) => {
-        resolve({
-            givenName : "Jean-Michel",
-            lastName : "Samarchepas",
-            uid : "jm",
-            birthdate : "dans le turfu",
-            mail : "email.email@email.com",
-            phone : "06 60 06 60 06",
-            groups : [],
-            likes : [],
-            address : "aussi dans le turfu"
-        });
-    });
-    /*return renseignerSurUtilisateur(user, userUID).then(res => {
-        return {
-            givenName : res[0].givenName,
-            lastName : res[0].lastName,
-            uid : userUID,
-            birthdate : res[0].brBirthdate,
-            mail : res[0].mail,
-            phone : res[0].telephoneNumber,
-            groups : [],
-            likes : [],
-            address : res[0].brRoom
-        };
-    });*/
-};
-
-export const getEvent = (user, eventID) => {
-    return null;
-};
-
-export const getGroup = (user, groupUID) => {
-    return null;
-};
\ No newline at end of file
diff --git a/src/graphql/resolvers.js b/src/graphql/resolvers.js
new file mode 100644
index 0000000000000000000000000000000000000000..24c05c153eccf64fa35833b5466292eb07aff507
--- /dev/null
+++ b/src/graphql/resolvers.js
@@ -0,0 +1,258 @@
+/**
+ * @file Implémentation des requêtes GraphQL.
+ * @author akka vodol
+*/
+import { request } from 'https';
+import _ from 'lodash';
+import { assertBinaryExpression } from 'babel-types';
+import knex from '../../db/knex_router';
+
+import * as connectors from './connectors/connectors.js';
+import { connect } from 'http2';
+
+/** 
+ * @description Résolveurs des différentes requêtes GraphQL
+*/
+export const resolvers = {
+    Query: {
+
+        asAdmin: (obj, args, context) => {
+            return connectors.hasAdminRights(context.user, args.groupUID).then(res => {
+                if(res)
+                    return {groupUID : args.groupUID};
+                else
+                    throw "You do not have admin rights over this group";
+            });
+        },
+
+        accessGroups: (obj, args, context) => {
+            return {};
+        },
+
+        accessPosts: (obj, args, context) => {
+            return {};
+        },
+
+        accessUsers: (obj, args, context) => {
+            return {};
+        },
+    },
+
+    GroupQuery : {
+        allGroups: (obj, args, context) => {
+            return connectors.getAllVisibleGroups(context.user);
+        },
+        group: (obj, args, context) => {
+            return connectors.getGroupIfVisible(context.user, args.uid);
+        },
+        simpleGroup: (obj, args, context) => {
+            return connectors.getSimpleGroupIfVisible(context.user, args.uid);
+        },
+        metaGroup: (obj, args, context) => {
+            return connectors.getMetaGroupIfVisible(context.user, args.uid);
+        }
+    },
+
+    MessageQuery : {
+        allPosts: (obj, args, context) => {
+            return knex.select().from('posts');
+        },
+        post: (obj, args, context) => {
+            const result = knex.select().from('posts').where('id','=',args.id);
+            return result.then((res) => res[0]);
+        },
+    },
+
+    UserQuery: {
+        user: (obj, args, context) => {
+            
+            return connectors.getUser(context.user,args.uid);
+        },
+
+        searchTOL: (obj, args, context) => {
+            console.log(args);
+            return connectors.repliquerTOLdesIds(context.user, {
+                givenName: args.givenName,
+                lastName: args.lastName,
+                nickname: args.nickname,
+                nationality: args.nationality,
+                school: args.school,
+                promotion: args.promotion,
+                groups: args.groups,
+                studies: args.studies,
+                sport: args.sport,
+                phone: args.phone,
+                mail: args.mail,
+                adress: args.adress,
+                ip: args.ip
+            });
+        }
+    },
+
+    AdminQuery: {
+        isAdmin: (obj, args, context) => {
+            return true;
+        },
+
+        allRequests: (obj, args, context) => {
+            console.log(obj);
+            return obj;
+        }
+    },
+
+    AllRequests: {
+        userJoinGroup : (obj, args, context) => {
+            return connectors.getUserJoinGroupRequests(context.user, obj.groupUID);
+        },
+
+        groupJoinEvent : (obj, args, context) => {
+            return connectors.getGroupJoinEventRequests(context.user, obj.groupUID);
+        },
+
+        yourGroupHostEvent : (obj, args, context) => {
+            return connectors.getYourGroupHostEventRequests(context.user, obj.groupUID);
+        },
+    },
+
+    UserJoinGroup: {
+        user : (obj, args, context) => {
+            return connectors.getUser(context.user, obj.useruid);
+            /*return connectors.getUser(context.user, "quentin.gendre");
+            if(obj.useruid === "anatole.romon"){
+                return connectors.getUser(context.user, "anatole.romon").then(res => {
+                    return connectors.getUser(context.user, "quentin.gendre");
+                });
+            }else{
+                return new Promise( (resolve, reject) => {
+                    resolve({givenName : "patrick"});
+                });
+            }*/
+        }
+    },
+
+    GroupJoinEvent : {
+        event: (obj, args, context) => {
+            return connectors.getEvent(context.user, obj.eventuid);
+        },
+        groupWantingToJoin: (obj, args, context) => {
+            return connectors.getGroup(context.user, obj.senderuid);
+        }
+    },
+
+    YourGroupHostEvent : {
+        event: (obj, args, context) => {
+            return connectors.getEvent(context.user, obj.eventuid);
+        },
+        sender: (obj, args, context) => {
+            return connectors.getGroup(context.user, obj.senderuid);
+        }
+    },
+
+    User : {
+        groups : (obj, args, context) => {
+            let result = Promise.all(obj.groups.map((grid) => {
+                return connectors.getSimpleGroup(context.user,grid);
+            }));
+
+            return result.then(groups => {
+                return _.filter(groups,(o) => !_.isUndefined(o));
+            });
+        },
+
+    },
+
+    Mutation: {
+        asAdmin: (obj, args, context) => {
+            return connectors.hasAdminRights(context.user, args.groupUID).then(res => {
+                if(res)
+                    return {groupUID : args.groupUID};
+                else
+                    throw "You do not have admin rights over this group";
+            });
+        },
+
+        asSpeaker: (obj, args, context) => {
+            return connectors.hasAdminRights(context.user, args.groupUID).then(res => {
+                if(res)
+                    return {groupUID : args.groupUID};
+                else
+                    throw "You do not have publishing rights in this group";
+            });
+        },
+
+        asMember: (obj, args, context) => {
+            return connectors.isMember(context.user, args.groupUID).then(res => {
+                if(res)
+                    return {groupUID : args.groupUID};
+                else
+                    throw "You are  not a member of this group";
+            });
+        },
+        asViewer: (obj, args, context) => {
+            return connectors.getGroupIfVisible(context.user, args.groupUID).then(res => {
+                if(res)
+                    return {groupUID : args.groupUID};
+                else
+                    throw "You are  not a member of this group";
+            });
+        }
+    },
+
+    AdminMutation: {
+        isAdmin: (obj, args, context) => {
+            return true;
+        
+        },
+        createSubgroup: (obj, args, context) => {
+            args.parentuid = obj.groupUID;
+            return connectors.createSubgroup(context.user, args);
+        },
+
+        editGroup: (obj, args, context) => {
+            return null;
+        }
+    },
+
+    ViewerMutation: {
+        requestJoin: (obj, args, context) => {
+            console.log(obj);
+            return null;
+        }
+    },
+
+    Post: {
+        authors: (obj, args, context) => {
+            return knex.select().from('groups').whereIn('uid',obj.authors);
+        }
+    },
+
+    Group: {
+        __resolveType: (obj) => {
+            
+            switch(obj.type){
+            case "simple":
+                return "SimpleGroup";
+            case "meta":
+                return "MetaGroup";
+            default:
+                return undefined;
+            }
+        }
+    },
+
+    SimpleGroup: {
+
+        members: (obj, args, context) => {
+            console.log("Current group is",obj.uid);
+            console.log("\tMembers of the group are:",obj);
+            return connectors.listerMembres(context.user,obj.uid);
+        }
+    },
+
+    MetaGroup: {
+
+        members: (obj, args, context) => {
+        }
+
+    }
+};
diff --git a/src/graphql/schema.js b/src/graphql/schema.js
index 0d96a92c93b7c5b5cedc73eb121e56ed899561a6..844298716a5bdcbb534a56d292732df1110c513f 100644
--- a/src/graphql/schema.js
+++ b/src/graphql/schema.js
@@ -2,249 +2,10 @@
  * @file Ce fichier génère le schéma GraphQL. C'est ici que les requêtes GraphQl sont résolues.
  * @author akka vodol
 */
+
 import { makeExecutableSchema } from 'graphql-tools';
-import { request } from 'https';
-import { assertBinaryExpression } from 'babel-types';
-import knex from '../../db/knex_router';
 import typeDefs from './typeDefs';
-
-import * as db_utils from './db_utils';
-
-/** 
- * @description Résolveurs des différentes requêtes GraphQL
-*/
-const resolvers = {
-    Query: {
-
-        asAdmin: (obj, args, context) => {
-            return db_utils.hasAdminRights(context.user, args.groupUID).then(res => {
-                if(res)
-                    return {groupUID : args.groupUID};
-                else
-                    throw "You do not have admin rights over this group";
-            });
-        },
-
-        allGroups: (obj, args, context) => {
-            return db_utils.getAllVisibleGroups(context.user);
-        },
-        group: (obj, args, context) => {
-            return db_utils.getGroupIfVisible(context.user, args.uid);
-        },
-        user: (obj, args, context) => {
-            const refactorer = (data) => {
-                return {
-                    uid: args.uid,
-                    lastName: data.sn,
-                    givenName: data.givenName,
-                    birthdate: data.brBirthdate,
-                    groups: data.brMemberOf,
-                    mail: data.mail,
-                    phone: data.telephoneNumber,
-                    room: data.brRoom
-                };
-            };
-
-            const result = db_utils.renseignerSurUtilisateur(context.user, args.uid).then(res => {
-                return refactorer(res[0]);
-            });
-
-            return result;
-        },
-
-        allPosts: (obj, args, context) => {
-            return knex.select().from('posts');
-        },
-        post: (obj, args, context) => {
-            const result = knex.select().from('posts').where('id','=',args.id);
-            return result.then((res) => res[0]);
-        },
-
-        searchTOL: (obj, args, context) => {
-            console.log(args);
-            return db_utils.repliquerTOLdesIds(context.user, {
-                givenName: args.givenName,
-                lastName: args.lastName,
-                nickname: args.nickname,
-                nationality: args.nationality,
-                school: args.school,
-                promotion: args.promotion,
-                groups: args.groups,
-                studies: args.studies,
-                sport: args.sport,
-                phone: args.phone,
-                mail: args.mail,
-                adress: args.adress,
-                ip: args.ip
-            });
-        }
-    },
-
-    AdminQuery: {
-        isAdmin: (obj, args, context) => {
-            return true;
-        },
-
-        allRequests: (obj, args, context) => {
-            console.log(obj);
-            return obj;
-        }
-    },
-
-    AllRequests: {
-        userJoinGroup : (obj, args, context) => {
-            return db_utils.getUserJoinGroupRequests(context.user, args.groupUID);
-        },
-    },
-
-    UserJoinGroup: {
-        user : (obj, args, context) => {
-            return db_utils.getUser(context.user, obj.useruid);
-            /*return db_utils.getUser(context.user, "quentin.gendre");
-            if(obj.useruid === "anatole.romon"){
-                return db_utils.getUser(context.user, "anatole.romon").then(res => {
-                    return db_utils.getUser(context.user, "quentin.gendre");
-                });
-            }else{
-                return new Promise( (resolve, reject) => {
-                    resolve({givenName : "patrick"});
-                });
-            }*/
-        }
-    },
-
-    GroupJoinEvent : {
-        event: (obj, args, context) => {
-            return db_utils.getEvent(context.user, obj.eventuid);
-        },
-        groupWantingToJoin: (obj, args, context) => {
-            return db_utils.getGroup(context.user, obj.senderuid);
-        }
-    },
-
-    YourGroupHostEvent : {
-        event: (obj, args, context) => {
-            return db_utils.getEvent(context.user, obj.eventuid);
-        },
-        sender: (obj, args, context) => {
-            return db_utils.getGroup(context.user, obj.senderuid);
-        }
-    },
-
-    /*User : {
-
-        givenName : (obj, args, context) => {
-            console.log("I got this")
-            return null;
-        },
-
-        lastName : (obj, args, context) => {
-            return null;
-        },
-
-        uid : (obj, args, context) => {
-            return null;
-        },
-
-        birthdate : (obj, args, context) => {
-            return null;
-        },
-
-        mail : (obj, args, context) => {
-            return null;
-        },
-
-        phone : (obj, args, context) => {
-            return null;
-        },
-
-        groups : (obj, args, context) => {
-            return null;
-        },
-
-        likes : (obj, args, context) => {
-            return null;
-        },
-
-        address : (obj, args, context) => {
-            return null;
-        }
-
-    },*/
-
-    Mutation: {
-        asAdmin: (obj, args, context) => {
-            return db_utils.hasAdminRights(context.user, args.groupUID).then(res => {
-                if(res)
-                    return {groupUID : args.groupUID};
-                else
-                    throw "You do not have admin rights over this group";
-            });
-        },
-
-        asSpeaker: (obj, args, context) => {
-            return db_utils.hasAdminRights(context.user, args.groupUID).then(res => {
-                if(res)
-                    return {groupUID : args.groupUID};
-                else
-                    throw "You do not have publishing rights in this group";
-            });
-        },
-
-        asMember: (obj, args, context) => {
-            return db_utils.isMember(context.user, args.groupUID).then(res => {
-                if(res)
-                    return {groupUID : args.groupUID};
-                else
-                    throw "You are  not a member of this group";
-            });
-        },
-        asViewer: (obj, args, context) => {
-            return db_utils.getGroupIfVisible(context.user, args.groupUID).then(res => {
-                if(res)
-                    return {groupUID : args.groupUID};
-                else
-                    throw "You are  not a member of this group";
-            });
-        }
-    },
-
-    AdminMutation: {
-        isAdmin: (obj, args, context) => {
-            return true;
-        
-        },
-        createSubgroup: (obj, args, context) => {
-            args.parentuid = obj.groupUID;
-            return db_utils.createSubgroup(context.user, args);
-        },
-
-        editGroup: (obj, args, context) => {
-            return null;
-        }
-    },
-
-    ViewerMutation: {
-        requestJoin: (obj, args, context) => {
-            console.log(obj);
-            return null;
-        }
-    },
-
-    Post: {
-        authors: (obj, args, context) => {
-            return knex.select().from('groups').whereIn('uid',obj.authors);
-        }
-    },
-
-    Group: {
-        members: (obj, args, context) => {
-            console.log("Current group is",obj.uid);
-            console.log("\tMembers of the group are:",obj);
-            return db_utils.listerMembres(context.user,obj.uid);
-        }
-    }
-};
+import { resolvers } from './resolvers';
 
 const schema = makeExecutableSchema({
     typeDefs,
diff --git a/src/graphql/typeDefs.js b/src/graphql/typeDefs.js
index 71686030bbe6969b47a8bcf0ed99ae41b5e56387..b77e9ea4bd531601dfba749d4aed7d7056145596 100644
--- a/src/graphql/typeDefs.js
+++ b/src/graphql/typeDefs.js
@@ -1,35 +1,15 @@
 const RootTypes = `
     # Requêtes
     type Query {
-        allGroups: [Group]
-        group(uid: ID) : Group
-        user(uid: ID) : User
-        allMessages: [Message]
-        allEvents: [Event]
-        allPosts: [Post]
-        post(id: ID): Post
-        allAnnouncements: [Announcement]
+        accessGroups : GroupQuery
+        accessPosts : MessageQuery
+        accessUsers : UserQuery
 
         asAdmin(groupUID: ID): AdminQuery
         asSpeaker(groupUID: ID): AdminQuery
         asMember(groupUID: ID): AdminQuery
         asViewer(groupUID: ID): AdminQuery
         
-        searchTOL(
-            givenName: String,
-            lastName: String,
-            nickname: String,
-            nationality: String,
-            school: String,
-            promotion: String,
-            groups: String,
-            studies: String,
-            sport: String,
-            phone: String,
-            mail: String,
-            adress: String,
-            ip: String
-        ): [String]
     }
 
     type Mutation {
@@ -86,6 +66,50 @@ const subMutations = `
 `;
 
 const subQueries = `
+
+    """
+    Requête pour obtenir un groupe.
+    """
+    type GroupQuery{
+        allGroups: [Group]
+        group(uid: ID) : Group
+        simpleGroup(uid : ID) : SimpleGroup
+        metaGroup(uid : ID) : MetaGroup
+
+    }
+
+    """
+    Requête pour obtenir un message.
+    """
+    type MessageQuery{
+        allMessages: [Message]
+        allEvents: [Event]
+        allPosts: [Post]
+        post(id: ID): Post
+        allAnnouncements: [Announcement]
+    }
+
+    type UserQuery{
+
+        user(uid: ID) : User
+
+        searchTOL(
+            givenName: String,
+            lastName: String,
+            nickname: String,
+            nationality: String,
+            school: String,
+            promotion: String,
+            groups: String,
+            studies: String,
+            sport: String,
+            phone: String,
+            mail: String,
+            adress: String,
+            ip: String
+        ): [String]
+    }
+
     # Requête à la base de donnée nécessitant d'être administrateur.
     type AdminQuery{
         isAdmin: Boolean
@@ -117,7 +141,7 @@ const User = `
         mail: String
         phone: String
         # Groupes dont l'utilisateur est membre.
-        groups: [Group]
+        groups: [SimpleGroup]
         # Groupes que l'utilisateur aime.
         likes: [Group]
         address: String
@@ -126,24 +150,56 @@ const User = `
 
 const Group = `
     # Groupes associatifs
-    type Group {
-        # Identifiant unique du groupe
+
+    """
+    L'interface Group représente les deux types de groupes implémentés dans Sigma : les groupes
+    simples, dont les membres sont des utilisateurs, et les métagroupes, dont les membres sont
+    des groupes simples (tel que Federez, dont les membres incluent le BR et DaTA). 
+    """
+    interface Group {
+        # Identifiant unique de l'union
         uid: ID
-        # Nom du groupe
+        # Nom de l'union
         name: String
         # Site du groupe
         website: String
+        # Le groupe est-il un spiritualGroup (sinon c'est un materialGroup)
+        createdAt: String!
+        updatedAt: String!
+
+    }
+
+    # Le groupe de base, dont les membres sont des utilisateurs. Binets, Kes, etc...
+    type SimpleGroup implements Group{
+        uid: ID
+        name: String
+        website: String
+        createdAt: String!
+        updatedAt: String!
+
         # Membres du groupe
         members: [User]
         # Jour et heure de création du groupe
-        createdAt: String!
-        updatedAt: String!
         description: String
         # École d'origine du groupe
         school: String
         # Groupe parent
         parent: Group
     }
+
+    # Anciennement appelé "interface dans les discussions"
+    # Un groupe dont les membre sont d'autres groupes
+    type MetaGroup implements Group {
+        uid: ID
+        name: String
+        website: String
+        createdAt: String!
+        updatedAt: String!
+
+        # Les groupes constitutifs du méta-groupe.
+        members: [Group]!
+    }
+
 `;
 
 const Message = `
diff --git a/src/ldap/ldap_data.js b/src/ldap/ldap_data.js
index dd10885b44566b24216210285f7d9b9537d7292e..76b28af83a261400781d0cd3cd8f3b9746cdee8e 100644
--- a/src/ldap/ldap_data.js
+++ b/src/ldap/ldap_data.js
@@ -32,7 +32,7 @@ var client = ldap.createClient({ url: config.ldap.server});
 //------------------------------------------------------------------------------------------------------------------------
 
 /**
- * @summary Fonction qui sert à s'identifier sur le LDAP. Renvoit rien.
+ * @summary Fonction qui sert à s'identifier sur le LDAP. Ne renvoie rien.
  * @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).
  * @arg {Object} user - Utilisateur de la forme suivante :
@@ -159,7 +159,7 @@ function listerGroupes(user, uid) {
  * @desc Cette fonction utilise {@link rechercherLDAP} avec un dictionnaire prédéfini dans config.json. Elle utilise LDAPEscape pour éviter les injections.
  * @arg {Object} user - Utilisateur de la forme nécessaire à {@link connecterLDAP}
  * @arg {string} gid - Identifiant du groupe à interroger (le plus souvent nom du groupe en minuscule)
- * @return {Promise(string[])} Liste des uid des membres où l'id fournie est membre (noms flat des groupes)
+ * @return {Promise(String[])} Liste des uid des membres où l'id fournie est membre (noms flat des groupes)
  */
 function listerMembres(user, gid) {
     return new Promise((resolve, reject) => {
@@ -199,8 +199,9 @@ function renseignerSurUtilisateur(user, uid) {
 //------------------------------------------------------------------------------------------------------------------------
 
 /**
- * @summary Fonction qui interroge le LDAP et retrouve les groupes (voir LDAP) qui ressemblent à l'input. Etape 0 vers un vrai TOL (Trombino On Line).
- * @desc Cette fonction utilise {@link rechercherLDAP} mais avec un filtre généré à la volée. Accepte des champs exacts ou incomplets mais pas approximatifs et ne gère pas l'auto-complete. Cette fonction utilise aussi [`ldap_config.json`](..\..\ldap_config.json). MEF Timeout pour des recherches trop vagues. Renvoit une liste d'uid. Elle utilise LDAPEscape pour éviter les injections.
+ * @summary Fonction qui interroge le LDAP et retrouve les groupes (voir LDAP) qui ressemblent
+ *  à l'entrée. Etape 0 vers un vrai TOL (Trombino On Line).
+ * @desc Cette fonction utilise {@link rechercherLDAP} mais avec un filtre généré à la volée. Accepte des champs exacts ou incomplets mais pas approximatifs et ne gère pas l'auto-complete. Cette fonction utilise aussi config.json. MEF Timeout pour des recherches trop vagues. Renvoit une liste d'uid. Elle utilise LDAPEscape pour éviter les injections.
  * @arg {Object} user - Utilisateur de la forme nécessaire à {@link connecterLDAP}
  * @arg {string} input - String entré par l'utilisateur qui ressemble au nom du groupe.
  * @return {Promise(string[])} Liste des uid de groupes dont le nom ressemble à l'input
@@ -887,7 +888,9 @@ function editerGroupe(user, gid, data) {
 //TBC
 /**
  * @summary Fonction qui supprime un utilisateur du LDAP.
- * @desc Cette fonction fait une utilisation massive d'eval pour anonymiser son code ; voir [`ldap_config.json`](..\..\ldap_config.json) pour le détail de la génération des champs finaux. Appelle {@link ajouterLDAP} bien sûr, mais aussi {@link ajouterMembreGroupe} et {@link ajouterAdministrateurGroupe} pour gérer les groupes du nouvel utilisateur.
+ * @desc Cette fonction fait une utilisation massive d'eval pour anonymiser son code ;
+ * voir ldap_config.json pour le détail de la génération des champs finaux. 
+ * Appelle {@link ajouterLDAP} bien sûr, mais aussi {@link ajouterMembreGroupe} et {@link ajouterAdministrateurGroupe} pour gérer les groupes du nouvel utilisateur.
  * @arg {Object} user - Utilisateur de la forme nécessaire à {@link connecterLDAP}
  * @arg {string} uid - uid de la victime
  * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
@@ -922,7 +925,10 @@ function supprimerUtilisateur(user, data) {
 //TBC
 /**
  * @summary Fonction qui supprime un 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 ajouterLDAP} et {@link modifierLDAP}, mais aussi {@link ajouterMembreGroupe} et {@link ajouterAdministrateurGroupe} pour gérer les groupes du nouvel utilisateur.
+ * @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 ajouterLDAP} 
+ * et {@link modifierLDAP}, mais aussi {@link ajouterMembreGroupe} et 
+ * {@link ajouterAdministrateurGroupe} pour gérer les groupes du nouvel utilisateur.
  * @arg {Object} user - Utilisateur de la forme nécessaire à {@link connecterLDAP}
  * @arg {string} gid - Identifiant du groupe à supprimer
  * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
diff --git a/src/server.js b/src/server.js
index c0019c071114f463a7fc15d1d9e677eee224b54a..af64a856f58d649243d5718806047a07a6b4e248 100644
--- a/src/server.js
+++ b/src/server.js
@@ -22,7 +22,6 @@ import path from 'path';
 import cors from 'cors';
 
 const server = express();
-
 // on sait pas a quoi ca sert mais il parait que c'est utile
 server.use(bodyParser.json());
 server.use(bodyParser.urlencoded({
@@ -114,7 +113,7 @@ server.use('/graphql', bodyParser.json(),
     }));
 
 // GraphiQL est une console interactive pour faire des requêtes au schéma GraphQL
-server.use('/graphiql', ensureLoggedIn('/login'), graphiqlExpress({endpointURL: '/graphql'}));
+server.use('/graphiql', /*ensureLoggedIn('/login'),*/ graphiqlExpress({endpointURL: '/graphql'}));
 
 // GraphQL voyager
 server.use('/voyager', graphqlVoyager({ endpointUrl: '/graphql' }));