Aller au contenu
Léo.
Tous les projets
Développement webTerminé2026

Breezy

Réseau social inspiré de X, découpé en six services indépendants derrière une passerelle unique.

CESI · Applications distribuées · Projet d'équipe

Illustration : services en réseau
Illustration : services en réseau
Rôle
Interface, service Post, service Notification
Équipe
4 développeurs, 417 commits
Services
6 microservices + passerelle + interface
Bases
2 PostgreSQL, 4 MongoDB

Points clés

  • Six services indépendants, chacun avec sa base, derrière une passerelle Nginx unique
  • Deux moteurs de base selon le besoin : relationnel pour les identités, documents pour les contenus
  • Bus d'événements RabbitMQ : publier un post ne dépend pas du service de notification
  • Temps réel par WebSocket pour la messagerie et les notifications

La démonstration

Démonstration : publication d'un post, notification reçue en temps réel par un autre compte, messagerie privée.

Comment ça marche

  1. 1

    Une seule porte d'entrée

    Tout passe par une passerelle Nginx sur le port 80 : l'interface comme les API. Elle porte ce qui n'a pas à être réécrit dans six services, la politique CORS, avec une liste d'origines autorisées, et la limitation de débit, réglée à 30 requêtes par seconde en général mais à 2 sur la connexion et l'inscription, là où on tente les mots de passe.

  2. 2

    Prouver qui l'on est

    Le service Auth vérifie le mot de passe, haché avec bcrypt, et signe un JWT. Pour les pages protégées, la passerelle ne devine rien : elle sous-traite la validation au service Auth avant de servir la page. Chaque service métier revérifie ensuite le jeton de son côté, aucun ne fait confiance à son appelant.

  3. 3

    Le service concerné répond

    Six domaines, six services, six bases : Auth et User sur PostgreSQL, Post, Message, Media et Notification sur MongoDB. Un domaine qui tombe n'emporte pas les autres, un service Média indisponible empêche d'ajouter une image, pas de lire le flux.

  4. 4

    L'événement se propage

    Quand un post est publié ou aimé, le service Post ne prévient pas le service Notification : il dépose un événement dans RabbitMQ et passe à la suite. Notification le consomme de son côté. Les deux services n'ont donc besoin ni de se connaître, ni d'être debout en même temps.

  5. 5

    L'écran se met à jour

    Notification et Message tiennent chacun une connexion WebSocket ouverte vers le navigateur. La notification apparaît sans rechargement, le message privé arrive pendant qu'on écrit, sans que l'interface ait à interroger le serveur en boucle.

Ce que fait l'application

Breezy fait ce qu'on attend d'un réseau social court : publier des posts et y répondre, aimer, suivre des comptes, chercher par contenu ou par tag, joindre images et vidéos, s'écrire en privé, recevoir des notifications. Les droits sont portés par quatre rôles, visiteur, utilisateur, modérateur, administrateur, et une vingtaine de permissions nommées, ce qui permet d'activer ou de couper une fonctionnalité sans toucher au code.

La contrainte du module

Le sujet imposait une architecture réellement distribuée, pas un monolithe déguisé en services. La difficulté n'est pas d'écrire six serveurs Express : c'est de choisir où passent les frontières, puis d'assumer ce que ce découpage coûte, une requête qui traverse trois processus, un état qui n'est plus partagé, des services qui démarrent dans le désordre.

Pourquoi deux moteurs de base

Le choix n'est pas décoratif, il suit la forme de la donnée.

  • PostgreSQL pour Auth et User : des comptes, des rôles, des permissions et des relations de suivi, des tables, des clés étrangères et des contraintes d'unicité, exactement ce qu'un moteur relationnel garantit mieux que du code applicatif
  • MongoDB pour Post, Message, Media et Notification : des documents qui varient d'un cas à l'autre, un post avec ou sans média, avec ou sans réponses, et qu'on lit presque toujours en entier
  • Chaque service possède sa base et personne d'autre n'y touche : c'est cette règle, plus que le découpage du code, qui rend les services réellement indépendants

La passerelle ne fait pas que router

  • Elle résout les noms des services à chaque requête plutôt qu'au démarrage : sans ça, un service encore en train de démarrer reste introuvable jusqu'au redémarrage de la passerelle
  • Elle applique un débit maximal différent selon la route, une limite globale, et une limite bien plus basse sur connexion et inscription
  • Elle centralise la politique CORS : une origine non autorisée ne reçoit aucun en-tête et se fait bloquer par le navigateur
  • Elle délègue la validation des jetons au service Auth pour les pages protégées, au lieu de reproduire une logique de sécurité dans la configuration

Ce que j'en retire

  • Découper un domaine en services : où placer les frontières, et le coût de se tromper
  • L'asynchrone n'est pas un détail d'implémentation, passer par un bus change qui dépend de qui
  • Un environnement complet reproductible en une commande, base de données et bus compris
  • Travail à quatre sur un dépôt commun, avec revue de code et branches de fonctionnalité
Tous les projets