Implémenter un éditeur collaboratif temps réel dans un SaaS (Yjs, WebSocket, PostgreSQL)
28/08/2026
implémenter un éditeur collaboratif temps réel dans un SaaS (Yjs, WebSocket, PostgreSQL)
Vous êtes CTO ou lead dev et vous devez ajouter une fonctionnalité d’édition collaborative (comme Google Docs) à votre logiciel métier ou SaaS ? Ce guide technique explique une architecture robuste et évolutive basée sur CRDT (Yjs), WebSocket, persistance PostgreSQL et montée en charge via Redis. À la fin vous aurez un plan clair, des snippets, des commandes Docker et les pièges à éviter.
pourquoi ce choix d’architecture
- Yjs (CRDT) évite les serveurs de résolution de conflits et fonctionne bien en offline-first.
- WebSocket pour la faible latence et la synchronisation temps réel des opérations.
- Redis pub/sub pour propager les mises à jour entre plusieurs instances de serveur WebSocket.
- PostgreSQL pour la persistance des états/versions (historique, snapshots) et requêtes relationnelles.
Si vous voulez explorer Yjs : documentation officielle Yjs. Pour la persistance relationnelle, la doc PostgreSQL est une bonne référence : PostgreSQL documentation.
architecture proposée (vue d’ensemble)
- Clients (navigateur / desktop) utilisent Yjs + y-websocket client pour produire/consommer opérations CRDT.
- Un cluster d’instances WebSocket (Node.js) reçoit les messages clients. Chaque instance applique localement les opérations Yjs.
- Redis pub/sub (ou Redis Streams) relaye les mises à jour entre instances pour garder tout le cluster cohérent.
- Un composant de persistance sérialise périodiquement (ou à checkpoint) l’état Yjs vers PostgreSQL (snapshots et logs d’édition).
- Authentification + autorisation tenant-aware (JWT / session) pour restreindre l’accès aux documents.
étapes de mise en œuvre avec exemples
1) Prototype local : lancer les dépendances
Commandes Docker pour monter rapidement Redis et PostgreSQL :
docker run -d --name redis -p 6379:6379 redis
docker run -d --name postgres -e POSTGRES_PASSWORD=secret -p 5432:5432 postgres
2) serveur WebSocket minimal (Node.js) — principe
Le serveur reçoit les opérations Yjs côté serveur et publie sur Redis. Ci‑dessous un pseudo‑snippet (conceptuel) ; adaptez selon vos packages (ws / uWebSockets / y-websocket).
// pseudo code - Node.js
const WebSocket = require('ws');
const Redis = require('redis');
const { applyUpdate, encodeStateAsUpdate } = require('yjs');
const wss = new WebSocket.Server({ port: 1234 });
const redisPub = Redis.createClient();
const redisSub = Redis.createClient();
wss.on('connection', (ws, req) => {
// authentifier l'utilisateur (JWT) et charger le document Yjs
ws.on('message', msg => {
// msg contient update Yjs : appliquer localement puis publier sur Redis
applyUpdate(doc, new Uint8Array(msg));
redisPub.publish('doc:1234', msg);
});
});
// recevoir les updates des autres instances
redisSub.subscribe('doc:1234');
redisSub.on('message', (channel, msg) => {
// diffuser aux clients connectés sur cette instance
wss.clients.forEach(client => client.send(msg));
});
Remarque : préférez des bibliothèques Yjs officielles comme y-websocket pour la production ; ici on montre le flux.
3) persistance : snapshots et journalisation
Stratégie recommandée :
- Enregistrer périodiquement un snapshot binaire Yjs dans PostgreSQL (colonne bytea) pour restauration rapide.
- Archiver les updates (opérationnel) si besoin d’audit ou de replay.
- Conserver index de version + métadonnées (user, tenant, timestamp).
-- schéma PostgreSQL exemple (simplifié)
CREATE TABLE doc_snapshot (
id uuid PRIMARY KEY,
document_id text,
tenant_id text,
snapshot bytea,
version bigint,
created_at timestamptz DEFAULT now()
);
Lors de la restauration, on charge le snapshot dans un document Yjs côté serveur puis on applique les updates récents.
4) montée en charge
- Utiliser plusieurs instances WebSocket derrière un load balancer. Si votre LB ne gère pas sticky sessions, Redis pub/sub assure la cohérence.
- Mesurez latence de bout en bout et visez <100 ms pour une bonne sensation utilisateur (objet métier dépendant).
- Surveillez ops/sec et mémoire par document : un document populaire peut devenir hot‑spot, shardlez-le (split par sous-documents ou sections).
exemples d’erreurs fréquentes et comment les éviter
- Fuite mémoire : ne conservez pas des documents Yjs en mémoire indéfiniment. Déchargez les documents inactifs et sauvegardez l’état.
- Storm d’événements : appliquer debouncing ou batching des updates pour persistance afin d’éviter pic IO.
- Perte de message Redis : si la durabilité est critique, considérez Redis Streams ou stockez les updates dans une file persistante.
- Conflits d’accès multi‑tenant : validez et vérifiez tenant_id à chaque requête WebSocket et avant d’appliquer/restaurer un snapshot.
sécurité et conformité
- Authentification forte sur le canal WebSocket (JWT avec vérification serveur).
- Chiffrement TLS pour les connexions WebSocket (wss://).
- Autorisation fine : vérifier que l’utilisateur a accès au document (tenant + roles).
- Audit : journalisez les événements d’écriture (utile pour conformité et rollback).
bonnes pratiques opérationnelles
- Tests de charge ciblés sur documents "hot" pour dimensionner Redis et instances WebSocket.
- Surveillance : métriques sur latence applyUpdate, taille des messages, mémoire par document, nombre de clients par document.
- Plan de sauvegarde/restauration : snapshots réguliers et testés sur des environnements staging.
- Favoriser modularité : séparer couche temps réel (WS + Redis) de la couche métier/Persistence (PostgreSQL).
outil et technologies conseillées
- Yjs (CRDT) pour la logique de merge côté client et serveur. Voir yjs.dev.
- Redis pour la propagation entre instances et pour limiter la latence inter‑nœud.
- PostgreSQL pour snapshots/queries relationnelles — utile si vous avez déjà un backoffice basé sur Postgres. (voir la doc officielle).
- Conteneurisation (Docker) et orchestrateur (Kubernetes) pour scalabilité ; utilisez des probes et autoscaling pour les instances temps réel.
- Stack observabilité (Prometheus + Grafana) pour métriques temps réel.
exemples concrets / métriques à viser
Indicateurs à surveiller lors d’un pilote :
- Latence de propagation (client→server→autres clients) : objectif <100 ms.
- Opérations par seconde par document : surveillez le seuil à partir duquel la mémoire ou le CPU explose.
- Taille moyenne des messages : gardez les updates compressés si >100 KB fréquemment.
conclusion
Implémenter un éditeur collaboratif dans un SaaS exige de combiner une logique de synchronisation résiliente (CRDT), une couche temps réel optimisée (WebSocket + Redis) et une persistance sûre (PostgreSQL). Le prototype commence simple (y-websocket + Docker) puis évolue vers un cluster avec monitoring et stratégies de snapshot. Cette approche vous donne un éditeur scalable, tolérant aux conflits et adapté à un contexte ERP/SaaS multitenant.
Pour aller plus loin, Novane accompagne la mise en production sécurisée et scalable de fonctionnalités temps réel dans des SaaS et logiciels métiers — découvrez nos services SaaS et nos réalisations techniques pour évaluer votre roadmap : services SaaS, PostgreSQL, Docker.
Besoin d’un audit ou d’un prototype rapide ? Contactez‑nous pour une séance de consulting.



