Blog

Gestion des commentaires sur les réseaux sociaux à grande échelle : Guide multi-plateformes

Découvrez comment créer une modération unifiée des commentaires sur plus de 8 plateformes avec des exemples TypeScript, une analyse de sentiment AI et un traite

Par

+8

Publiez partout. Une API.

Try Free

La gestion des commentaires sur plusieurs plateformes sociales est devenue l'un des défis les plus exigeants pour les marques et les développeurs. Efficace modération des commentaires sur les réseaux sociaux nécessite de gérer des API, des formats de données et des limites de taux très différents tout en maintenant des temps de réponse cohérents pour votre communauté. Ce guide vous accompagne dans la création d'un système prêt pour la production qui agrège, normalise et traite les commentaires de Facebook, Instagram, Twitter, YouTube, LinkedIn, Reddit, Bluesky et Threads.

À la fin de cet article, vous disposerez d'un code TypeScript fonctionnel pour un système de gestion des commentaires unifié capable de gérer des millions d'interactions par jour.

Le défi des commentaires multi-plateformes

Chaque plateforme sociale gère les commentaires de manière différente. Facebook regroupe les réponses sous les commentaires principaux avec des jetons de pagination. Instagram associe les commentaires aux objets médias avec des limites de fréquence strictes. YouTube utilise une API complètement distincte des autres services de Google. Twitter (X) considère les réponses comme des publications ordinaires dans un fil de conversation.

Ces différences engendrent trois problèmes majeurs :

Incohérence des donnéesChaque plateforme renvoie des champs différents, formate les horodatages de manière distincte et structure les données utilisateur de façons uniques. Un « commentaire » sur YouTube n’a rien à voir avec une « réponse » sur Twitter en termes de réponse API.

Complexité des limites de tauxFacebook autorise 200 appels par heure par jeton utilisateur. L'API v2 de Twitter propose un accès par paliers avec des limites différentes. YouTube impose des unités de quota plutôt que de simples comptes de requêtes. Gérer ces limites sur différentes plateformes nécessite un contrôle de flux sophistiqué.

Attentes en temps réelLes utilisateurs attendent des réponses quasi instantanées. Lorsque quelqu'un commente votre publication Instagram, il ne se soucie pas du fait que vous surveillez également sept autres plateformes. Votre système doit agréger les commentaires rapidement sans atteindre les limites de fréquence.

Voici la réalité à laquelle vous êtes confronté :

PlatformStyle d'APILimites de tauxStructure des Commentaires
FacebookGraph API200 appels/heure/utilisateurImbriqué avec pagination
InstagramGraph API200 appels/heure/utilisateurPlat, attaché aux médias
Twitter/XREST + DiffusionTarification par paliers (10K-1M/mois)Fil de conversation
YouTubeAPI de données v310 000 unités de quota/jourFil de discussion avec réponses
LinkedInAPI REST100 appels/jour (variable)Organisation uniquement
RedditOAuth REST60 requêtes/minuteArbres profondément imbriqués
BlueskyProtocole AT3 000 points/5 minPlat avec références de réponse
ThreadsGraph APIPartagé avec InstagramSimilaire à Instagram

Comparaison des plateformes : Fonctionnalités et limitations

Avant d'écrire du code, il est essentiel de comprendre ce que chaque plateforme prend réellement en charge. Toutes les plateformes ne fournissent pas les données de commentaires via leur API, et certaines imposent des restrictions importantes.

type InboxFeature = 'messages' | 'comments' | 'reviews';

const INBOX_PLATFORMS = {
  messages: ['facebook', 'instagram', 'twitter', 'bluesky', 'reddit', 'telegram'] as const,
  // TikTok et Pinterest exclus : leurs API ne prennent pas en charge la lecture des commentaires
  comments: ['facebook', 'instagram', 'twitter', 'bluesky', 'threads', 'youtube', 'linkedin', 'reddit'] as const,
  reviews: ['facebook', 'googlebusiness'] as const,
} as const;

type CommentsPlatform = (typeof INBOX_PLATFORMS.comments)[number];

function isPlatformSupported(platform: string, feature: InboxFeature): boolean {
  return (INBOX_PLATFORMS[feature] as readonly string[]).includes(platform);
}

function validatePlatformSupport(
  platform: string,
  feature: InboxFeature
): { valid: true } | { valid: false; error: string; supportedPlatforms: readonly string[] } {
  if (!isPlatformSupported(platform, feature)) {
    const featureLabel = feature === 'messages' ? 'messages direct' : feature;
    return {
      valid: false,
      error: `La plateforme '${platform}' ne prend pas en charge ${featureLabel}`,
      supportedPlatforms: INBOX_PLATFORMS[feature],
    };
  }
  return { valid: true };
}

Note : TikTok et Pinterest ne proposent pas de support pour les commentaires. Leurs API n'exposent pas les données de commentaires pour la lecture, uniquement pour la publication dans des scénarios limités. Planifiez votre stratégie multi-plateformes en conséquence.

LinkedIn présente un cas particulier. La plateforme n'autorise l'accès aux commentaires que pour les pages d'organisation (entreprises), et non pour les profils personnels. Votre système doit valider cela :

function isLinkedInOrgAccount(
  metadata: Map | Record | null | undefined
): boolean {
  if (!metadata) return false;

  // Gérer Mongoose Map (courant dans les schémas MongoDB)
  if (metadata instanceof Map) {
    return metadata.get('accountType') === 'organization' || metadata.has('selectedOrganization');
  }

  // Gérer objet simple
  return metadata.accountType === 'organization' || 'selectedOrganization' in metadata;
}

function filterAccountsForFeature(
  accounts: SocialAccount[],
  feature: InboxFeature
): SocialAccount[] {
  const supportedPlatforms = INBOX_PLATFORMS[feature] as readonly string[];

  return accounts.filter((account) => {
    if (!supportedPlatforms.includes(account.platform)) {
      return false;
    }

    // LinkedIn nécessite un type de compte organisation pour les fonctionnalités de la boîte de réception
    if (account.platform === 'linkedin' && !isLinkedInOrgAccount(account.metadata)) {
      return false;
    }

    return true;
  });
}

Modèle de données de commentaires unifié

La base d'une communication efficace gestion des commentaires multi-plateformes est un modèle de données normalisé. La structure des commentaires de chaque plateforme doit correspondre à une interface unique avec laquelle la logique de votre application peut fonctionner de manière cohérente.

interface UnifiedComment {
  // Identification
  id: string;                          // Unique dans votre système
  platformId: string;                  // ID original de la plateforme
  platform: CommentsPlatform;
  accountId: string;                   // Compte connecté
  
  // Contenu
  text: string;
  textHtml?: string;                   // Texte enrichi si disponible
  attachments: CommentAttachment[];
  
  // Auteur
  author: {
    id: string;
    username: string;
    displayName: string;
    avatarUrl?: string;
    profileUrl?: string;
    isVerified: boolean;
  };
  
  // Contexte
  postId: string;                      // Publication/vidéo/média parent
  parentCommentId?: string;            // Pour les réponses imbriquées
  threadId?: string;                   // Fil de conversation
  
  // Métadonnées
  createdAt: Date;
  updatedAt?: Date;
  likeCount: number;
  replyCount: number;
  
  // Modération
  status: 'pending' | 'approved' | 'hidden' | 'deleted';
  sentiment?: 'positive' | 'neutral' | 'negative';
  sentimentScore?: number;             // -1 à 1
  flags: string[];                     // spam, offensant, etc.
  
  // Données spécifiques à la plateforme (échappatoire)
  rawData?: Record;
}

interface CommentAttachment {
  type: 'image' | 'video' | 'link' | 'sticker' | 'gif';
  url: string;
  thumbnailUrl?: string;
  width?: number;
  height?: number;
}

Ce modèle capture les champs essentiels tout en préservant les données spécifiques à chaque plateforme dans rawData pour les cas particuliers. Le status and sentiment les champs prennent en charge les flux de modération que nous construirons plus tard.

Agrégation des commentaires sur plusieurs plateformes

Avec votre modèle de données défini, vous avez besoin d'une infrastructure pour récupérer les commentaires de plusieurs comptes simultanément. Les principaux défis sont de gérer les pannes de manière élégante (une plateforme en panne ne devrait pas tout faire échouer) et de gérer les délais d'attente.

interface AggregationError {
  accountId: string;
  accountUsername?: string;
  platform: string;
  error: string;
  code?: string;
  retryAfter?: number;
}

interface AggregatedResult {
  items: T[];
  errors: AggregationError[];
}

async function aggregateFromAccounts(
  accounts: SocialAccount[],
  fetcher: (account: SocialAccount) => Promise,
  options?: { timeout?: number }
): Promise> {
  const timeout = options?.timeout || 10000; // délai par défaut de 10 secondes
  const results: T[] = [];
  const errors: AggregationError[] = [];

  const fetchPromises = accounts.map(async (account) => {
    try {
      const timeoutPromise = new Promise((_, reject) => {
        setTimeout(() => reject(new Error('Délai d\'attente dépassé')), timeout);
      });

      const items = await Promise.race([fetcher(account), timeoutPromise]);
      return { account, items, error: null };
    } catch (error: unknown) {
      const err = error as Error & { code?: string; retryAfter?: number };
      return {
        account,
        items: [] as T[],
        error: {
          accountId: account._id?.toString() || account.id,
          accountUsername: account.username,
          platform: account.platform,
          error: err.message || 'Erreur inconnue',
          code: err.code,
          retryAfter: err.retryAfter,
        },
      };
    }
  });

  const settledResults = await Promise.all(fetchPromises);

  for (const result of settledResults) {
    if (result.error) {
      errors.push(result.error);
    } else {
      results.push(...result.items);
    }
  }

  return { items: results, errors };
}

Ce modèle permet un succès partiel. Si votre jeton Facebook expire mais que Twitter fonctionne correctement, vous continuez à recevoir les commentaires Twitter tout en enregistrant l'erreur Facebook pour une nouvelle tentative.

Stratégies de Normalisation des Commentaires

Chaque plateforme renvoie des commentaires dans des formats différents. Vous avez besoin de fonctions de transformation qui convertissent les réponses spécifiques à chaque plateforme en votre modèle unifié. Voici comment structurer ces normalisateurs :

type CommentNormalizer = (
  rawComment: unknown,
  account: SocialAccount,
  postId: string
) => UnifiedComment;

const normalizers: Record = {
  facebook: normalizeFacebookComment,
  instagram: normalizeInstagramComment,
  twitter: normalizeTwitterComment,
  youtube: normalizeYouTubeComment,
  linkedin: normalizeLinkedInComment,
  reddit: normalizeRedditComment,
  bluesky: normalizeBlueskyComment,
  threads: normalizeThreadsComment,
};

function normalizeFacebookComment(
  raw: FacebookCommentResponse,
  account: SocialAccount,
  postId: string
): UnifiedComment {
  return {
    id: `fb_${raw.id}`,
    platformId: raw.id,
    platform: 'facebook',
    accountId: account._id.toString(),
    text: raw.message || '',
    attachments: raw.attachment ? [{
      type: mapFacebookAttachmentType(raw.attachment.type),
      url: raw.attachment.url,
      thumbnailUrl: raw.attachment.media?.image?.src,
    }] : [],
    author: {
      id: raw.from.id,
      username: raw.from.id, // Facebook ne fournit pas le nom d'utilisateur
      displayName: raw.from.name,
      avatarUrl: `https://graph.facebook.com/${raw.from.id}/picture`,
      profileUrl: `https://facebook.com/${raw.from.id}`,
      isVerified: false, // Non disponible dans la réponse de base
    },
    postId,
    parentCommentId: raw.parent?.id ? `fb_${raw.parent.id}` : undefined,
    createdAt: new Date(raw.created_time),
    likeCount: raw.like_count || 0,
    replyCount: raw.comment_count || 0,
    status: raw.is_hidden ? 'hidden' : 'approved',
    flags: [],
    rawData: raw,
  };
}

function normalizeTwitterComment(
  raw: TwitterTweetResponse,
  account: SocialAccount,
  postId: string
): UnifiedComment {
  const author = raw.includes?.users?.find(u => u.id === raw.data.author_id);
  
  return {
    id: `tw_${raw.data.id}`,
    platformId: raw.data.id,
    platform: 'twitter',
    accountId: account._id.toString(),
    text: raw.data.text,
    attachments: extractTwitterAttachments(raw.data, raw.includes),
    author: {
      id: raw

Le modèle de normalisation maintient la logique spécifique à chaque plateforme isolée. Lorsque Twitter modifie son API (ce qui arrive fréquemment), vous n'avez qu'à mettre à jour une seule fonction.

Build faster with Late

One API call to post everywhere. No OAuth headaches. No platform-specific code.

Free tier • No credit card • 99.97% uptime

Création de flux de travail de modération

L'agrégation de commentaires bruts n'est que le début. Efficace modération des commentaires sur les réseaux sociaux nécessite des flux de travail pour examiner, répondre et agir sur les commentaires. Voici une approche par machine d'état :

type ModerationAction = 
  | 'approuver'
  | 'cacher'
  | 'supprimer'
  | 'répondre'
  | 'signaler'
  | 'escalader'
  | 'attribuer';

interface ModerationRule {
  id: string;
  name: string;
  conditions: RuleCondition[];
  actions: ModerationAction[];
  priority: number;
  enabled: boolean;
}

interface RuleCondition {
  field: keyof UnifiedComment | 'author.isVerified' | 'sentiment';
  operator: 'égal' | 'contient' | 'correspond' | 'supérieur' | 'inférieur';
  value: string | number | boolean | RegExp;
}

class ModerationEngine {
  private rules: ModerationRule[] = [];

  addRule(rule: ModerationRule): void {
    this.rules.push(rule);
    this.rules.sort((a, b) => b.priority - a.priority);
  }

  async processComment(comment: UnifiedComment): Promise<{
    actions: ModerationAction[];
    matchedRules: string[];
  }> {
    const matchedRules: string[] = [];
    const actions: Set = new Set();

    for (const rule of this.rules) {
      if (!rule.enabled) continue;

      const matches = this.evaluateConditions(comment, rule.conditions);
      if (matches) {
        matchedRules.push(rule.id);
        rule.actions.forEach(action => actions.add(action));
      }
    }

    return {
      actions: Array.from(actions),
      matchedRules,
    };
  }

  private evaluateConditions(
    comment: UnifiedComment,
    conditions: RuleCondition[]
  ): boolean {
    return conditions.every(condition => {
      const value = this.getFieldValue(comment, condition.field);
      return this.evaluateCondition(value, condition.operator, condition.value);
    });
  }

  private getFieldValue(comment: UnifiedComment, field: string): unknown {
    const parts = field.split('.');
    let value: unknown = comment;
    for (const part of parts) {
      if (value && typeof value === 'object') {
        value = (value as Record)[part];
      } else {
        return undefined;
      }
    }
    return value;
  }

  private evaluateCondition(
    fieldValue: unknown,
    operator: RuleCondition['operator'],
    ruleValue: RuleCondition['value']
  ): boolean

Exemples de règles que vous pourriez configurer :

const moderationEngine = new ModerationEngine();

// Masquer automatiquement les commentaires contenant des grossièretés
moderationEngine.addRule({
  id: 'filtre-grossièretés',
  name: 'Masquer les Grossièretés',
  conditions: [
    { field: 'text', operator: 'matches', value: /\b(mauvaismot1|mauvaismot2)\b/i }
  ],
  actions: ['masquer', 'signaler'],
  priority: 100,
  enabled: true,
});

// Escalader le sentiment négatif des utilisateurs vérifiés
moderationEngine.addRule({
  id: 'verifié-négatif',
  name: 'Escalader Négatif Vérifié',
  conditions: [
    { field: 'author.isVerified', operator: 'equals', value: true },
    { field: 'sentiment', operator: 'equals', value: 'négatif' }
  ],
  actions: ['escalader'],
  priority: 90,
  enabled: true,
});

// Approuver automatiquement les commentaires des utilisateurs fréquents
moderationEngine.addRule({
  id: 'commentateur-de-confiance',
  name: 'Approuver Automatiquement les Fiables',
  conditions: [
    { field: 'author.id', operator: 'contains', value: 'liste_de_confiance' }
  ],
  actions: ['approuver'],
  priority: 80,
  enabled: true,
});

Analyse de sentiment alimentée par l'IA

Modern API de modération des commentaires les implémentations tirent parti de l'IA pour l'analyse des sentiments et la détection de toxicité. Vous pouvez intégrer OpenAI ou d'autres fournisseurs pour classer automatiquement les commentaires :

interface SentimentResult {
  sentiment: 'positif' | 'neutre' | 'négatif';
  score: number;        // -1 à 1
  confidence: number;   // 0 à 1
  toxicity?: number;    // 0 à 1
  categories?: string[]; // spam, haine, harcèlement, etc.
}

async function analyzeCommentSentiment(
  comment: UnifiedComment,
  openaiApiKey: string
): Promise {
  const response = await fetch('https://api.openai.com/v1/chat/completions', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${openaiApiKey}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      model: 'gpt-4o-mini',
      messages: [
        {
          role: 'system',
          content: `Analyse le sentiment des commentaires sur les réseaux sociaux. Retourne un JSON avec :
- sentiment : "positif", "neutre" ou "négatif"
- score : nombre de -1 (très négatif) à 1 (très positif)
- confiance : nombre de 0 à 1
- toxicité : nombre de 0 à 1 (0 = pas toxique, 1 = très toxique)
- catégories : tableau d'étiquettes applicables parmi [spam, haine, harcèlement, menace, auto-agression, sexuel, aucun]`
        },
        {
          role: 'user',
          content: `Analyse ce commentaire :\n\n"${comment.text}"\n\nContexte : C'est un commentaire sur ${comment.platform} sur un post d'une marque.`
        }
      ],
      response_format: { type: 'json_object' },
      temperature: 0.1,
    }),
  });

  if (!response.ok) {
    throw new Error(`Erreur API OpenAI : ${response.status}`);
  }

  const data = await response.json();
  const result = JSON.parse(data.choices[0].message.content);

  return {
    sentiment: result.sentiment,
    score: result.score,
    confidence: result.confidence,
    toxicity: result.toxicity,
    categories: result.categories?.filter((c: string) => c !== 'aucun'),
  };
}

// Traitement par lot pour

Note : Pour des scénarios à fort volume, envisagez d'utiliser des API de modération dédiées comme Perspective API (gratuit pour un usage modéré) ou AWS Comprehend, qui sont optimisées pour ce cas d'utilisation et plus rentables que GPT-4 pour une classification simple.

Architecture de traitement basée sur des files d'attente

To automatiser les commentaires sur les réseaux sociaux À grande échelle, vous avez besoin d'un traitement asynchrone. Une architecture basée sur des files d'attente découple l'ingestion des commentaires du traitement, vous permettant de gérer les pics de trafic avec aisance.

interface CommentJob {
  type: 'fetch' | 'analyze' | 'moderate' | 'respond';
  commentId?: string;
  accountId: string;
  platform: CommentsPlatform;
  payload: Record;
  attempts: number;
  maxAttempts: number;
  createdAt: Date;
  scheduledFor: Date;
}

class CommentProcessingQueue {
  private queue: CommentJob[] = [];
  private processing: boolean = false;
  private concurrency: number = 5;

  async enqueue(job: Omit): Promise {
    this.queue.push({
      ...job,
      attempts: 0,
      createdAt: new Date(),
    });
    
    this.queue.sort((a, b) => 
      a.scheduledFor.getTime() - b.scheduledFor.getTime()
    );

    if (!this.processing) {
      this.processQueue();
    }
  }

  private async processQueue(): Promise {
    this.processing = true;

    while (this.queue.length > 0) {
      const now = new Date();
      const readyJobs = this.queue.filter(j => j.scheduledFor <= now);
      
      if (readyJobs.length === 0) {
        // Attendre le prochain travail programmé
        const nextJob = this.queue[0];
        const waitTime = nextJob.scheduledFor.getTime() - now.getTime();
        await new Promise(resolve => setTimeout(resolve, Math.min(waitTime, 1000)));
        continue;
      }

      // Traiter jusqu'à la limite de concurrence
      const batch = readyJobs.slice(0, this.concurrency);
      
      await Promise.all(batch.map(async (job) => {
        this.queue = this.queue.filter(j => j !== job);
        
        try {
          await this.processJob(job);
        } catch (error) {
          await this.handleJobError(job, error as Error);
        }
      }));
    }

    this.processing = false;
  }

  private async processJob(job: CommentJob): Promise {
    job.attempts++;

    switch (job.type) {
      case 'fetch':
        await this.handleFetchJob(job);
        break;
      case 'analyze':
        await this.handleAnalyzeJob(job);
        break;
      case 'moderate':
        await this.handleModerateJob(job);
        break;
      case '

Pour les systèmes de production, remplacez cette file d'attente en mémoire par Redis (en utilisant BullMQ) ou un service géré comme AWS SQS.

Performance à grande échelle

Lors du traitement de milliers de commentaires par minute, de petites inefficacités s'accumulent. Voici des optimisations essentielles :

DeduplicationLes commentaires peuvent apparaître dans plusieurs récupérations, surtout lors de sondages fréquents.

function deduplicateItems(
  items: T[],
  keyFn: (item: T) => string
): T[] {
  const seen = new Set();
  return items.filter((item) => {
    const key = keyFn(item);
    if (seen.has(key)) return false;
    seen.add(key);
    return true;
  });
}

// Utilisation
const uniqueComments = deduplicateItems(
  allComments,
  (comment) => `${comment.platform}_${comment.platformId}`
);

Pagination basée sur le curseurLa pagination par décalage devient lente avec de grands ensembles de données. Utilisez des curseurs qui encodent la position :

interface PaginationInfo {
  hasMore: boolean;
  nextCursor: string | null;
  totalCount?: number;
}

function paginateWithCursor<T extends { id?: string; _id?: unknown }>(
  items: T[],
  cursor: string | null,
  limit: number,
  getTimestamp: (item: T) => string,
  getAccountId: (item: T) => string
): { items: T[]; pagination: PaginationInfo } {
  let filteredItems = items;

  // Format du curseur : {timestamp}_{accountId}_{itemId}
  if (cursor) {
    const [cursorTimestamp, cursorAccountId, cursorItemId] = cursor.split('_');
    const cursorTime = new Date(cursorTimestamp).getTime();

    filteredItems = items.filter((item) => {
      const itemTime = new Date(getTimestamp(item)).getTime();
      const itemAccountId = getAccountId(item);
      const itemId = item.id || String(item._id);

      if (itemTime < cursorTime) return true;
      if (itemTime === cursorTime) {
        if (itemAccountId > cursorAccountId) return true;
        if (itemAccountId === cursorAccountId && itemId > cursorItemId) return true;
      }
      return false;
    });
  }

  const paginatedItems = filteredItems.slice(0, limit);
  const hasMore = filteredItems.length > limit;

  let nextCursor: string | null = null;
  if (hasMore && paginatedItems.length > 0) {
    const lastItem = paginatedItems[paginatedItems.length - 1];
    nextCursor = `${getTimestamp(lastItem)}_${getAccountId(lastItem)}_${lastItem.id || lastItem._id}`;
  }

  return {
    items: paginatedItems,
    pagination: { hasMore, nextCursor },
  };
}

Tri efficace: Pré-triez par champs communs et maintenez les index :

function trierElements<T>(
  elements: T[],
  trierPar: string,
  ordreDeTri: 'asc' | 'desc',
  carteDesChamps: Record<string, (element: T) => unknown>
): T[] {
  const recuperateur = carteDesChamps[trierPar];
  if (!recuperateur) return elements;

  return [...elements].sort((a, b) => {
    const aValeur = recuperateur(a);
    const bValeur = recuperateur(b);

    // Gestion des dates
    if (aValeur instanceof Date && bValeur instanceof Date) {
      return ordreDeTri === 'asc'
        ? aValeur.getTime() - bValeur.getTime()
        : bValeur.getTime() - aValeur.getTime();
    }

    // Gestion des nombres
    if (typeof aValeur === 'number' && typeof bValeur === 'number') {
      return ordreDeTri === 'asc' ? aValeur - bValeur : bValeur - aValeur;
    }

    // Gestion des chaînes
    if (typeof aValeur === 'string' && typeof bValeur === 'string') {
      return ordreDeTri === 'asc'
        ? aValeur.localeCompare(bValeur)
        : bValeur.localeCompare(aValeur);
    }

    return 0;
  });
}

Fonctionnalités de collaboration en équipe

La gestion des commentaires en entreprise nécessite des flux de travail d'équipe. Plusieurs modérateurs doivent collaborer sans se gêner mutuellement :

interface CommentAssignment {
  commentId: string;
  assignedTo: string;        // ID de l'utilisateur
  assignedBy: string;
  assignedAt: Date;
  status: 'en_attente' | 'en_cours' | 'terminé';
  notes?: string;
}

interface ModerationAuditLog {
  id: string;
  commentId: string;
  action: ModerationAction;
  performedBy: string;
  performedAt: Date;
  previousState: Partial;
  newState: Partial;
  reason?: string;
}

class TeamModerationService {
  async assignComment(
    commentId: string,
    assignTo: string,
    assignedBy: string
  ): Promise {
    // Vérifier si déjà assigné
    const existing = await this.getAssignment(commentId);
    if (existing && existing.status === 'en_cours') {
      throw new Error(`Commentaire déjà assigné à ${existing.assignedTo}`);
    }

    const assignment: CommentAssignment = {
      commentId,
      assignedTo: assignTo,
      assignedBy,
      assignedAt: new Date(),
      status: 'en_attente',
    };

    await this.saveAssignment(assignment);
    return assignment;
  }

  async logAction(
    commentId: string,
    action: ModerationAction,
    userId: string,
    previousState: Partial,
    newState: Partial,
    reason?: string
  ): Promise {
    const log: ModerationAuditLog = {
      id: generateId(),
      commentId,
      action,
      performedBy: userId,
      performedAt: new Date(),
      previousState,
      newState,
      reason,
    };

    await this.saveAuditLog(log);
  }

  async getCommentHistory(commentId: string): Promise {
    return this.findAuditLogs({ commentId });
  }

  // Méthodes abstraites pour l'implémentation du stockage
  protected async getAssignment(commentId: string): Promise {
    throw new Error('Non implémenté');
  }
  protected async saveAssignment(assignment: CommentAssignment): Promise {
    throw new Error('Non implémenté');
  }
  protected async saveAuditLog(log: ModerationAuditLog): Promise {
    throw new Error('

Utiliser Late pour la gestion des commentaires

Construire et maintenir une infrastructure de commentaires multi-plateformes est complexe. Vous devez gérer huit API différentes, chacune avec ses propres flux d'authentification, limites de taux, formats de données et systèmes de webhook. Lorsque les plateformes mettent à jour leurs API (ce qui arrive constamment), votre code se casse.

Late fournit une API unifiée pour la modération des commentaires sur les réseaux sociaux qui gère toute cette complexité. Au lieu de créer des intégrations séparées pour Facebook, Instagram, Twitter, YouTube, LinkedIn, Reddit, Bluesky et Threads, vous utilisez un seul point de terminaison.

Les fonctionnalités de gestion des commentaires de Late incluent :

  • Boîte de réception unifiéeTous les commentaires de toutes les plateformes dans un format normalisé.
  • Agrégation en temps réel: Commentaires récupérés automatiquement grâce à un sondage intelligent
  • Gestion des erreurs intégréeLes pannes de la plateforme ne font pas tomber votre système.
  • Collaboration d'équipe: Attribution, journaux d'audit et accès basé sur les rôles
  • Support des WebhooksRecevez des notifications instantanées pour les nouveaux commentaires.

Voici à quel point la récupération des commentaires devient simple avec Late :

// Au lieu de 8 intégrations d'API différentes...
const response = await fetch('https://api.getlate.dev/v1/inbox/comments', {
  headers: {
    'Authorization': `Bearer ${LATE_API_KEY}`,
  },
});

const { comments, pagination, meta } = await response.json();

// comments: UnifiedComment[] - déjà normalisés
// pagination: { hasMore, nextCursor }
// meta: { accountsQueried, accountsFailed, failedAccounts }

Late gère la complexité spécifique à chaque plateforme : rafraîchissement des tokens OAuth, gestion des limites de taux, vérification des webhooks et normalisation des données. Vous vous concentrez sur la création de vos flux de modération et de l'expérience utilisateur.

Découvrez La documentation de Late pour consulter la référence complète de l'API de la boîte de réception, y compris le filtrage par plateforme, l'intégration de l'analyse de sentiment et les actions de modération en masse.


La gestion des commentaires sur plusieurs plateformes est un problème résolu si vous utilisez les bons outils. Que vous construisiez l'infrastructure vous-même en suivant les modèles de ce guide ou que vous tiriez parti de l'API unifiée de Late, l'essentiel est de concevoir pour l'échelle dès le départ : modèles de données normalisés, traitement asynchrone, gestion des erreurs élégante et flux de travail adaptés aux équipes.

Une API. 13+ plateformes.

Intégrez les réseaux sociaux en minutes, pas en semaines.

Conçu pour les développeurs. Apprécié par les agences. Fiable pour 6 325 utilisateurs.