diff --git a/src/graphql/resolvers/groups.ts b/src/graphql/resolvers/groups.ts
index a6711351b82c7d9cab187f7b5df21e63a90b1645..0e0885c206433fa34abb9be4998d094fc59d7e6e 100644
--- a/src/graphql/resolvers/groups.ts
+++ b/src/graphql/resolvers/groups.ts
@@ -4,7 +4,8 @@
  */
 
 import {Authorisation} from '../connectors/authorisation';
-import {User} from './users'
+import {User} from './users';
+import {Announcement, Event, PrivatePost, Question, Answer} from './messages';
 import {Group as LDAP_Group} from '../../ldap/export/group';
 import knex from '../../../db/knex_router';
 
diff --git a/src/graphql/resolvers/messages.js b/src/graphql/resolvers/messages.js
deleted file mode 100644
index 85c9d8feedfce053f4cad059fa7602d2d5a82994..0000000000000000000000000000000000000000
--- a/src/graphql/resolvers/messages.js
+++ /dev/null
@@ -1,121 +0,0 @@
-/**
- * @file Resolvers pour tous les types de messages. hawkspar->akka ; bien, mais pas suffisant
- * @author akka
- */
-import * as connectors from '../connectors/connectors';
-
-const MessageResolvers = {
-    Message: {
-        __resolveType: function(obj) {
-            if (obj.location) {
-                return "Event";
-            }
-            if (obj.views) {
-                return "Announcement";
-            }
-            if (obj.for_question) {
-                return "Answer";
-            }
-            if (obj.for_answer) {
-                return "Question";
-            }
-            return "PrivatePost";
-        }
-    },
-
-    Announcement: {
-        forEvent : function(obj, args, context){
-            // le champ is_announcement n'existe que sur les Events
-            // une ligne de la bdd events peut résoudre comme évènement ou comme annonce
-            if(obj.is_announcement) 
-                return obj;
-            else
-                return null;
-        },
-
-        authors: async function (obj, args, context){
-            return connectors.getMessageGroupAuthors(context.user, obj.id);
-        },
-
-        recipients: async function (obj, args, context){
-            return connectors.getMessageGroupRecipients(context.user, obj.id);
-        },
-
-    },
-
-    Event: {
-
-        startTime: function (obj) {
-            return obj.start_time;
-        },
-
-        endTime: function (obj) {
-            return obj.end_time;
-        },
-
-        asAnnouncement: function (obj, args, context) {
-            // le champ is_announcement indique si il existe une annonce qui va avec l'évènement
-            // une ligne de la bdd events peut résoudre comme évènement ou comme annonce
-            if (obj.is_announcement)
-                return obj;
-            else
-                return null;
-        },
-
-        authors: async function (obj, args, context) {
-            return connectors.getMessageGroupAuthors(context.user, obj.id);
-        },
-
-        recipients: async function (obj, args, context) {
-            return connectors.getMessageGroupRecipients(context.user, obj.id);
-        }
-    },
-
-
-
-    PrivatePost : {
-
-        authors: async function(obj, args, context){
-            return connectors.getUser(context.user, obj.author_uid, obj.author_db);
-            
-        },
-
-        recipients: async function(obj, args, context){
-            return connectors.getGroup(context.user, obj.recipient_uid);
-            
-        }
-    },
-
-    Question : {
-
-        authors: async function(obj, args, context){
-            return connectors.getUser(context.user, obj.author_uid, obj.author_db);
-        },
-
-        recipients: async function(obj, args, context){
-            return connectors.getGroup(context.user, obj.recipient_uid);
-        },
-
-        forAnswer: function(obj, args, context){
-            return obj.for_answer;
-        }
-    },
-
-    Answer : {
-
-        authors: async function(obj, args, context){
-            return connectors.getGroup(context.user, obj.author_uid);
-        },
-
-        recipients: async function(obj, args, context){
-            return connectors.getGroup(context.user, obj.recipient_uid);
-        },
-
-        forQuestion: function(obj, args, context){
-            return obj.for_question;
-
-        },
-    }
-};
-
-export default MessageResolvers;
\ No newline at end of file
diff --git a/src/graphql/resolvers/messages.ts b/src/graphql/resolvers/messages.ts
new file mode 100644
index 0000000000000000000000000000000000000000..01c81e4a4b55103c72f46f675692d7f595e9801e
--- /dev/null
+++ b/src/graphql/resolvers/messages.ts
@@ -0,0 +1,718 @@
+/**
+ * @file Resolvers pour tous les types de messages
+ * @author akka, ofacklam
+ */
+
+import {Group, SimpleGroup, MetaGroup} from './groups';
+import {User} from './users';
+import knex from '../../../db/knex_router';
+
+export abstract class Message {
+
+    /**
+     * @memberof GraphQL
+     * @class Message
+     * @summary Resolvers des messages
+     * @classdesc Une classe abstraite représentant l'interface Message du schéma.
+     * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement.
+     * @arg {number} mid - Identifiant du message, supposé valide.
+     * @rights dépend du type de message
+     * @abstract
+     */
+    constructor(mid: number) {
+        this.mid = mid;
+        this.m_dataLoaded = false;
+    }
+
+    /**
+     * @memberof GraphQL.Message#
+     * @function fetchData
+     * @summary Fonction qui va chercher toutes les données sur ce message dans la BDD, si ce n'est pas déja fait.
+     * @async
+     * @protected
+     * @abstract
+     */
+    protected abstract async fetchData(): Promise<void>
+
+    /**
+     * Protected properties.
+     * Ce sont tous les champs triviaux, ie qui peuvent etre récupérés en une seule requete a la BDD,
+     * ce qui permet d'etre plus efficace.
+     * La variable dataLoaded témoigne de si on est déja allés chercher les données.
+     * ATTENTION. Ce ne sont PAS directement les resolvers, il FAUT donc qu'ils aient un nom DIFFÉRENT du nom des champs dans le schéma.
+     */
+    protected m_dataLoaded: boolean
+    
+    protected m_createdAt: string
+    protected m_updatedAt: string
+    protected m_title: string
+    protected m_content: string
+
+    /**
+     * Ci-dessous les resolvers a proprement parler.
+     */
+
+    /**
+     * @memberof GraphQL.Message#
+     * @function __resolveType
+     * @summary Renvoie quel type de Message c'est
+     * @return {string}
+     * @rights same as message object
+     */
+    __resolveType(): string {
+        if (this instanceof Announcement) {
+            return "Announcement";
+        }
+        else if (this instanceof Event) {
+            return "Event";
+        }
+        else if (this instanceof Question) {
+            return "Question";
+        }
+        else if (this instanceof Answer) {
+            return "Answer";
+        }
+        else if (this instanceof PrivatePost) {
+            return "PrivatePost";
+        }
+        else {
+            throw "Mauvais type de message";
+        }
+    }
+
+    /** @rights same as message object */
+    mid: number;
+
+    /**
+     * @memberof GraphQL.Message#
+     * @function createdAt
+     * @summary Renvoie la date de création
+     * @return {Promise(string)}
+     * @rights same as message object
+     * @async
+     */
+    async createdAt(args, context, info): Promise<string> {
+        await this.fetchData();
+        return this.m_createdAt;
+    }
+
+    /**
+     * @memberof GraphQL.Message#
+     * @function updatedAt
+     * @summary Renvoie la date de mise a jour
+     * @return {Promise(string)}
+     * @rights same as message object
+     * @async
+     */
+    async updatedAt(args, context, info): Promise<string> {
+        await this.fetchData();
+        return this.m_updatedAt;
+    }
+
+    /**
+     * @memberof GraphQL.Message#
+     * @function title
+     * @summary Renvoie le titre du message
+     * @return {Promise(string)}
+     * @rights same as message object
+     * @async
+     */
+    async title(args, context, info): Promise<string> {
+        await this.fetchData();
+        return this.m_title;
+    }
+
+    /**
+     * @memberof GraphQL.Message#
+     * @function content
+     * @summary Renvoie le contenu du message
+     * @return {Promise(string)}
+     * @rights same as message object
+     * @async
+     */
+    async content(args, context, info): Promise<string> {
+        await this.fetchData();
+        return this.m_content;
+    }
+}
+
+export class Announcement extends Message {
+
+    /**
+     * @memberof GraphQL
+     * @class Announcement
+     * @extends GraphQL.Message
+     * @summary Resolvers des announcements
+     * @classdesc Une classe représentant le type Announcement du schéma.
+     * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement.
+     * @arg {number} mid - Identifiant du message, supposé valide.
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     */
+    constructor(mid: number) {
+        super(mid);
+    }
+
+    /**
+     * @memberof GraphQL.Announcement#
+     * @function fetchData
+     * @summary Fonction qui va chercher toutes les données sur cet announcement dans la BDD, si ce n'est pas déja fait.
+     * @async
+     * @protected
+     */
+    protected async fetchData(): Promise<void> {
+        if(!this.m_dataLoaded) {
+            let data = await knex.select('created_at',
+                'updated_at',
+                'title',
+                'content',
+                //'importance', 
+                'views').from('messages_announcements').where('mid', this.mid);
+
+            if (data.length() > 0) {
+                let m = data[0];
+
+                this.m_createdAt = m.created_at;
+                this.m_updatedAt = m.updated_at;
+                this.m_title = m.title;
+                this.m_content = m.content;
+                //this.m_importance = m.importance;
+                this.m_views = m.views;
+
+                this.m_dataLoaded = true;
+            }
+        }
+    }
+
+    /**
+     * Protected properties.
+     * Ce sont tous les champs triviaux, ie qui peuvent etre récupérés en une seule requete a la BDD,
+     * ce qui permet d'etre plus efficace.
+     * La variable dataLoaded témoigne de si on est déja allés chercher les données.
+     * ATTENTION. Ce ne sont PAS directement les resolvers, il FAUT donc qu'ils aient un nom DIFFÉRENT du nom des champs dans le schéma.
+     */
+    protected m_importance: number
+    protected m_views : number
+
+    /**
+     * Ci-dessous les resolvers a proprement parler.
+     */
+
+    /**
+     * @memberof GraphQL.Announcement#
+     * @function authors
+     * @summary Renvoie les groupes auteurs
+     * @return {Promise(Group[])}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    async authors(args, context, info): Promise<Group[]> {
+        throw "Not implemented";
+    }
+
+    /**
+     * @memberof GraphQL.Announcement#
+     * @function recipients
+     * @summary Renvoie les groupes destinataires
+     * @return {Promise(Group[])}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    async recipients(args, context, info): Promise<Group[]> {
+        throw "Not implemented";
+    }
+
+    /**
+     * @memberof GraphQL.Announcement#
+     * @function importance
+     * @summary Renvoie l'importance
+     * @return {Promise(number)}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    async importance(args, context, info): Promise<number> {
+        await this.fetchData();
+        return this.m_importance;
+    }
+
+    /**
+     * @memberof GraphQL.Announcement#
+     * @function views
+     * @summary Renvoie le nombre de vues
+     * @return {Promise(number)}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    async views(args, context, info): Promise<number> {
+        await this.fetchData();
+        return this.m_views;
+    }
+
+    /**
+     * @memberof GraphQL.Announcement#
+     * @function forEvent
+     * @summary Renvoie l'evenement correspondant, s'il existe
+     * @return {Promise(Event)}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    async forEvent(args, context, info): Promise<Event> {
+        let data = await knex.select('mid').from('messages_events').where('for_announcement', this.mid);
+        if(data.length() > 0) {
+            return new Event(data[0].mid);
+        }
+        return null;
+    }
+}
+
+export class Event extends Message {
+
+    /**
+     * @memberof GraphQL
+     * @class Event
+     * @extends GraphQL.Message
+     * @summary Resolvers des events
+     * @classdesc Une classe représentant le type Event du schéma.
+     * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement.
+     * @arg {number} mid - Identifiant du message, supposé valide.
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     */
+    constructor(mid: number) {
+        super(mid);
+    }
+
+    /**
+     * @memberof GraphQL.Event#
+     * @function fetchData
+     * @summary Fonction qui va chercher toutes les données sur cet event dans la BDD, si ce n'est pas déja fait.
+     * @async
+     * @protected
+     */
+    protected async fetchData(): Promise<void> {
+        if (!this.m_dataLoaded) {
+            let data = await knex.select('created_at',
+                'updated_at',
+                'title',
+                'content',
+                'location', 
+                'start_time', 
+                'end_time', 
+                'for_announcement').from('messages_events').where('mid', this.mid);
+
+            if (data.length() > 0) {
+                let m = data[0];
+
+                this.m_createdAt = m.created_at;
+                this.m_updatedAt = m.updated_at;
+                this.m_title = m.title;
+                this.m_content = m.content;
+                this.m_location = m.location;
+                this.m_startTime = m.start_time;
+                this.m_endTime = m.end_time;
+                this.m_forAnnouncement = m.for_announcement;
+
+                this.m_dataLoaded = true;
+            }
+        }
+    }
+
+    /**
+     * Protected properties.
+     * Ce sont tous les champs triviaux, ie qui peuvent etre récupérés en une seule requete a la BDD,
+     * ce qui permet d'etre plus efficace.
+     * La variable dataLoaded témoigne de si on est déja allés chercher les données.
+     * ATTENTION. Ce ne sont PAS directement les resolvers, il FAUT donc qu'ils aient un nom DIFFÉRENT du nom des champs dans le schéma.
+     */
+    protected m_location: string
+    protected m_startTime: string
+    protected m_endTime: string
+    protected m_forAnnouncement: number
+
+    /**
+     * Ci-dessous les resolvers a proprement parler.
+     */
+
+    /**
+     * @memberof GraphQL.Event#
+     * @function authors
+     * @summary Renvoie les groupes auteurs
+     * @return {Promise(Group[])}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    async authors(args, context, info): Promise<Group[]> {
+        throw "Not implemented";
+    }
+
+    /**
+     * @memberof GraphQL.Event#
+     * @function recipients
+     * @summary Renvoie les groupes destinataires
+     * @return {Promise(Group[])}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    async recipients(args, context, info): Promise<Group[]> {
+        throw "Not implemented";
+    }
+
+    /**
+     * @memberof GraphQL.Event#
+     * @function location
+     * @summary Renvoie l'endroit
+     * @return {Promise(string)}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    async location(args, context, info): Promise<string> {
+        await this.fetchData();
+        return this.m_location;
+    }
+    
+    /**
+     * @memberof GraphQL.Event#
+     * @function startTime
+     * @summary Renvoie l'horaire de début
+     * @return {Promise(string)}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    async startTime(args, context, info): Promise<string> {
+        await this.fetchData();
+        return this.m_startTime;
+    }
+
+    /**
+     * @memberof GraphQL.Event#
+     * @function endTime
+     * @summary Renvoie l'horaire de fin
+     * @return {Promise(string)}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    async endTime(args, context, info): Promise<string> {
+        await this.fetchData();
+        return this.m_endTime;
+    }
+
+    /**
+     * @memberof GraphQL.Event#
+     * @function participatingGroups
+     * @summary Renvoie les groupes qui participent
+     * @return {Promise(Group[])}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    async participatingGroups(args, context, info): Promise<Group[]> {
+        throw "Not implemented";
+    }
+
+    /**
+     * @memberof GraphQL.Event#
+     * @function participatingUsers
+     * @summary Renvoie les users qui participent
+     * @return {Promise(User[])}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    async participatingUsers(args, context, info): Promise<User[]> {
+        throw "Not implemented";
+    }
+
+    /**
+     * @memberof GraphQL.Event#
+     * @function forAnnouncement
+     * @summary Renvoie l'announcement correspondant, s'il existe
+     * @return {Promise(Announcement)}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    async forAnnouncement(args, context, info): Promise<Announcement> {
+        await this.fetchData();
+        if (this.m_forAnnouncement == 0) { //what is the default ?????
+            return null;
+        } 
+        else {
+            return new Announcement(this.m_forAnnouncement);
+        }
+    }
+}
+
+export class PrivatePost extends Message {
+
+    /**
+     * @memberof GraphQL
+     * @class PrivatePost
+     * @extends GraphQL.Message
+     * @summary Resolvers des posts privés
+     * @classdesc Une classe représentant le type PrivatePost du schéma.
+     * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement.
+     * @arg {number} mid - Identifiant du message, supposé valide.
+     * @rights membre du groupe recipient
+     */
+    constructor(mid: number) {
+        super(mid);
+    }
+
+    /**
+     * @memberof GraphQL.PrivatePost#
+     * @function fetchData
+     * @summary Fonction qui va chercher toutes les données sur ce post privé dans la BDD, si ce n'est pas déja fait.
+     * @async
+     * @protected
+     */
+    protected async fetchData(): Promise<void> {
+        if (!this.m_dataLoaded) {
+            let data = await knex.select('created_at',
+                'updated_at',
+                'title',
+                'content',
+                'author',
+                'recipient').from('messages_private_posts').where('mid', this.mid);
+
+            if (data.length() > 0) {
+                let m = data[0];
+
+                this.m_createdAt = m.created_at;
+                this.m_updatedAt = m.updated_at;
+                this.m_title = m.title;
+                this.m_content = m.content;
+                this.m_author = m.author;
+                this.m_recipient = m.recipient;
+
+                this.m_dataLoaded = true;
+            }
+        }
+    }
+
+    /**
+     * Protected properties.
+     * Ce sont tous les champs triviaux, ie qui peuvent etre récupérés en une seule requete a la BDD,
+     * ce qui permet d'etre plus efficace.
+     * La variable dataLoaded témoigne de si on est déja allés chercher les données.
+     * ATTENTION. Ce ne sont PAS directement les resolvers, il FAUT donc qu'ils aient un nom DIFFÉRENT du nom des champs dans le schéma.
+     */
+    protected m_author: string
+    protected m_recipient: string
+
+    /**
+     * Ci-dessous les resolvers a proprement parler.
+     */
+
+    /**
+     * @memberof GraphQL.Event#
+     * @function author
+     * @summary Renvoie le user auteur
+     * @return {Promise(User)}
+     * @rights membre du groupe recipient
+     * @async
+     */
+    async author(args, context, info): Promise<User> {
+        await this.fetchData();
+        return new User(this.m_author);
+    }
+
+    /**
+     * @memberof GraphQL.Event#
+     * @function recipient
+     * @summary Renvoie le groupe destinataire
+     * @return {Promise(Group)}
+     * @rights membre du groupe recipient
+     * @async
+     */
+    async recipient(args, context, info): Promise<Group> {
+        await this.fetchData();
+        throw "Not implemented";
+    }
+}
+
+export class Question extends Message {
+
+    /**
+     * @memberof GraphQL
+     * @class Question
+     * @extends GraphQL.Message
+     * @summary Resolvers des questions
+     * @classdesc Une classe représentant le type Question du schéma.
+     * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement.
+     * @arg {number} mid - Identifiant du message, supposé valide.
+     * @rights viewer du groupe recipient
+     */
+    constructor(mid: number) {
+        super(mid);
+    }
+
+    /**
+     * @memberof GraphQL.Question#
+     * @function fetchData
+     * @summary Fonction qui va chercher toutes les données sur ce post privé dans la BDD, si ce n'est pas déja fait.
+     * @async
+     * @protected
+     */
+    protected async fetchData(): Promise<void> {
+        if (!this.m_dataLoaded) {
+            let data = await knex.select('created_at',
+                'updated_at',
+                'title',
+                'content',
+                'author',
+                'recipient').from('messages_questions').where('mid', this.mid);
+
+            if (data.length() > 0) {
+                let m = data[0];
+
+                this.m_createdAt = m.created_at;
+                this.m_updatedAt = m.updated_at;
+                this.m_title = m.title;
+                this.m_content = m.content;
+                this.m_author = m.author;
+                this.m_recipient = m.recipient;
+
+                this.m_dataLoaded = true;
+            }
+        }
+    }
+
+    /**
+     * Protected properties.
+     * Ce sont tous les champs triviaux, ie qui peuvent etre récupérés en une seule requete a la BDD,
+     * ce qui permet d'etre plus efficace.
+     * La variable dataLoaded témoigne de si on est déja allés chercher les données.
+     * ATTENTION. Ce ne sont PAS directement les resolvers, il FAUT donc qu'ils aient un nom DIFFÉRENT du nom des champs dans le schéma.
+     */
+    protected m_author: string
+    protected m_recipient: string
+
+    /**
+     * Ci-dessous les resolvers a proprement parler.
+     */
+
+    /**
+     * @memberof GraphQL.Question#
+     * @function author
+     * @summary Renvoie le user auteur
+     * @return {Promise(User)}
+     * @rights viewer du groupe recipient
+     * @async
+     */
+    async author(args, context, info): Promise<User> {
+        await this.fetchData();
+        return new User(this.m_author);
+    }
+
+    /**
+     * @memberof GraphQL.Question#
+     * @function recipient
+     * @summary Renvoie le groupe destinataire
+     * @return {Promise(Group)}
+     * @rights viewer du groupe recipient
+     * @async
+     */
+    async recipient(args, context, info): Promise<Group> {
+        await this.fetchData();
+        throw "Not implemented";
+    }
+
+    /**
+     * @memberof GraphQL.Question#
+     * @function forAnswer
+     * @summary Renvoie la réponse correspondante, si elle existe
+     * @return {Promise(Answer)}
+     * @rights viewer du groupe recipient
+     * @async
+     */
+    async forAnswer(args, context, info): Promise<Answer> {
+        let data = await knex.select('mid').from('messages_answers').where('for_question', this.mid);
+        if (data.length() > 0) {
+            return new Answer(data[0].mid);
+        }
+        return null;
+    }
+}
+
+export class Answer extends Message {
+
+    /**
+     * @memberof GraphQL
+     * @class Answer
+     * @extends GraphQL.Message
+     * @summary Resolvers des réponses
+     * @classdesc Une classe représentant le type Answer du schéma.
+     * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement.
+     * @arg {number} mid - Identifiant du message, supposé valide.
+     * @rights viewer du groupe author
+     */
+    constructor(mid: number) {
+        super(mid);
+    }
+
+    /**
+     * @memberof GraphQL.Answer#
+     * @function fetchData
+     * @summary Fonction qui va chercher toutes les données sur ce post privé dans la BDD, si ce n'est pas déja fait.
+     * @async
+     * @protected
+     */
+    protected async fetchData(): Promise<void> {
+        if (!this.m_dataLoaded) {
+            let data = await knex.select('created_at',
+                'updated_at',
+                'title',
+                'content',
+                'recipient', //<--- WTF ????
+                'for_question').from('messages_answers').where('mid', this.mid);
+
+            if (data.length() > 0) {
+                let m = data[0];
+
+                this.m_createdAt = m.created_at;
+                this.m_updatedAt = m.updated_at;
+                this.m_title = m.title;
+                this.m_content = m.content;
+                this.m_author = m.recipient;
+                this.m_forQuestion = m.for_question;
+
+                this.m_dataLoaded = true;
+            }
+        }
+    }
+
+    /**
+     * Protected properties.
+     * Ce sont tous les champs triviaux, ie qui peuvent etre récupérés en une seule requete a la BDD,
+     * ce qui permet d'etre plus efficace.
+     * La variable dataLoaded témoigne de si on est déja allés chercher les données.
+     * ATTENTION. Ce ne sont PAS directement les resolvers, il FAUT donc qu'ils aient un nom DIFFÉRENT du nom des champs dans le schéma.
+     */
+    protected m_author: string
+    protected m_forQuestion: number
+
+    /**
+     * Ci-dessous les resolvers a proprement parler.
+     */
+
+    /**
+     * @memberof GraphQL.Answer#
+     * @function author
+     * @summary Renvoie le groupe auteur
+     * @return {Promise(Group)}
+     * @rights viewer du groupe author
+     * @async
+     */
+    async author(args, context, info): Promise<Group> {
+        await this.fetchData();
+        throw "Not implemented";
+    }
+
+    /**
+     * @memberof GraphQL.Answer#
+     * @function forQuestion
+     * @summary Renvoie la question correspondante
+     * @return {Promise(Question)}
+     * @rights viewer du groupe author
+     * @async
+     */
+    async forQuestion(args, context, info): Promise<Question> {
+        await this.fetchData();
+        return new Question(this.m_forQuestion);
+    }
+}
diff --git a/src/graphql/resolvers/users.ts b/src/graphql/resolvers/users.ts
index d1263e77ce62b567b08338bc47db1f4bf5d40e58..4a856aacd04a9f5e00b707d670656b113ad29f36 100644
--- a/src/graphql/resolvers/users.ts
+++ b/src/graphql/resolvers/users.ts
@@ -4,8 +4,9 @@
  */
 
 import {Group, SimpleGroup, MetaGroup} from './groups';
+import {Question} from './messages';
 import {User as LDAP_User} from '../../ldap/export/user';
-import {Tools, GroupSet} from '../connectors/tools'
+import {Tools, GroupSet} from '../connectors/tools';
 
 export class User {
 
@@ -309,7 +310,7 @@ export class User {
      * @function questionsFromUser
      * @summary Renvoie les questions que le user a posées
      * @return {Promise(Question[])}
-     * @rights connectedOrOnplatal
+     * @rights viewer of recipient group
      * @async
      */
     async questionsFromUser(args, context, info): Promise<Question[]> {
diff --git a/src/graphql/typeDefs/objects.graphql b/src/graphql/typeDefs/objects.graphql
index d3d83a80b020b62a3b9c3b77da16fa297ef33f57..32449557bebb61efa2ecfad5bd04c1776cfc3e52 100644
--- a/src/graphql/typeDefs/objects.graphql
+++ b/src/graphql/typeDefs/objects.graphql
@@ -174,7 +174,7 @@ interface Message {
     content: String!
 
     #authors: AuthorUnion
-    recipient: Group
+    #recipient: Group
 }
 
 # Annonce effectuée par un ou plusieurs groupes.
@@ -186,7 +186,7 @@ type Announcement implements Message {
     content: String!
 
     authors: [Group]
-    recipient: Group
+    recipients: [Group]
 
     importance: Int # importance de cette Announcement, sur une échelle de [??] à [??] (TODO)
     views: Int # nombre de vues
@@ -204,7 +204,7 @@ type Event implements Message {
     content: String!
 
     authors: [Group] # Organisateurs de l'événement
-    recipient: Group
+    recipients: [Group]
 
     location: String!
     startTime: String!
@@ -226,7 +226,7 @@ type PrivatePost implements Message {
     title: String!
     content: String!
 
-    authors: User
+    author: User
     recipient: Group
 }
 
@@ -238,7 +238,7 @@ type Question implements Message {
     title: String!
     content: String!
 
-    authors: User
+    author: User
     recipient: Group
 
     # Référence la réponse donnée par le groupe à cette Question. Si pas encore répondu, null.
@@ -253,8 +253,7 @@ type Answer implements Message {
     title: String!
     content: String!
 
-    authors: Group
-    recipient: Group # doit être le même que authors
+    author: Group
 
     # La question à laquelle cette Answer répond. Non-nullable bien sûr
     forQuestion: Question!