Le modèle en 10 minutes

Cinq notions, lues dans l'ordre : le message, le catalogue, le broker, l'objet standard, le canal. Tout le reste du site les décline.

1. Le message

Un message est une enveloppe à clé unique : le nom du message, et son payload.

{ message_demande: { ref: "3f2c8a9e-…", texte: "bonjour" } }

Le payload est de la donnée JSON pure : string, number, boolean, object, array. Jamais une Date, une instance de classe, une fonction ou un handle. Un message doit se comporter à l'identique qu'il soit livré localement (copie) ou à travers le réseau (texte JSON).

Chaque champ est déclaré au catalogue. Aucun champ implicite : un champ en trop fait rejeter le message, comme un champ manquant.

2. Le catalogue

Le catalogue décrit chaque message par un contrat : des versions, des révisions, des champs typés, et des exemples qui prouvent le tout. C'est de la pure donnée, injectée au broker à la construction. Voici le contrat réel de message_demande dans le chat :

Vocabulaire : type, required, pattern, enum, default, fields pour un sous-objet, items pour une liste, et oneOf au niveau d'une révision pour « exactement un champ parmi N ». Aucune règle conditionnelle par valeur : ce vocabulaire est fermé, et c'est voulu. Le tableau complet.

Une révision ajoute des champs de façon compatible. Une version casse la forme et vient avec un upcaster déclaratif. Un contrat validé ne se modifie jamais en place.

3. Le broker

Un par environnement : un dans le navigateur, un sur le serveur. Il fait trois choses, et il les fait strictement.

Le broker ne connaît aucun composant par son nom. Il connaît des émetteurs et des abonnés par message.

4. L'objet standard

Un composant est une classe à la signature unique, client et serveur : (broker, instanceName, deps). Le squelette tient en une page :

class StandardObject {

	instanceName;      // différencie une instance d'une autre
	broker;            // l'aiguilleur auprès duquel l'objet s'inscrit et par lequel il émet
	deps;              // tout le reste : supports DOM, pools, sockets, réglages
	supports;          // les nœuds HTML du rendu, normalisés en carte
	support;           // raccourci vers supports.main
	verbose = false;

	emits    = [{ name: "some_message", version: 1 }];
	receives = [{ name: "other_message", version: 1 }]; // un abonné ne déclare JAMAIS de révision

	constructor(broker, instanceName, deps = {}) {
		this.broker = broker;
		this.instanceName = instanceName;
		this.deps = deps;
		this.supports = deps.support?.nodeType ? { main: deps.support } : (deps.support ?? {});
		this.support  = this.supports.main;
		this.render(); // objets client seulement
		this.broker.register(this, this.emits, this.receives);
	}

	handleMessage(message) {
		// selon les clés présentes : rafraîchir l'affichage et/ou publier
		// this.broker.publish(this, { some_message: { … } });
	}

	destroy() { // symétrique du constructeur
		this.broker.unregister(this, this.emits, this.receives);
		for (const node of Object.values(this.supports)) node.replaceChildren();
	}

}
export default StandardObject;

Tout ce qui n'est ni le broker ni le nom d'instance arrive par deps, à la construction : un support DOM, un pool de base de données déjà ouvert, un socket. Jamais de process.env, jamais d'import de configuration. Les cinq règles de deps.

5. Le canal

Client et serveur ont chacun leur broker. Un canal est un objet standard comme les autres, abonné des deux côtés : ce qu'un client émet, la moitié client du canal le reçoit et l'envoie ; la moitié serveur le publie auprès du broker serveur, qui le valide à nouveau. Rien ne parle jamais directement au canal.

navigateur serveur ecran_fil broker client canal (client) canal (serveur) broker serveur gestion_messages publish réseau publish handleMessage aller : message_demande — ecran_fil ▶ broker client ▶ canal ▶ réseau ▶ canal ▶ broker serveur ▶ gestion_messages retour : message_poste — gestion_messages ▶ broker serveur ▶ canal ▶ réseau ▶ canal ▶ broker client ▶ ecran_fil
Le trajet aller-retour d'un message du chat. Chaque broker valide ce qu'il publie ; les deux moitiés du canal importent le même fichier de catalogue.

Le trajet d'un message_demande, étape par étape

  1. ecran_fil publie

    L'utilisateur envoie « bonjour ». Le composant tire un ref (UUID) et publie { message_demande: { ref, texte } } auprès de son broker.

  2. Le broker client valide

    Contre message_demande v1 r0 : ref doit ressembler à un UUID, texte faire entre 1 et 1000 caractères. Validé : mis en file, puis livré aux abonnés. Ici le seul abonné est le canal.

  3. Le canal client envoie la trame

    Il reçoit le message dans son handleMessage comme n'importe quel abonné, et l'écrit sur le socket en JSON.

  4. Le canal serveur publie

    Il pose id (identifiant de session) et session (l'objet partagé) sur l'enveloppe, consulte allowMessage, puis publie. Le broker serveur valide à nouveau le payload : un client modifié ne peut rien injecter hors contrat.

  5. gestion_messages traite et répond

    Il vérifie que la session est identifiée, enregistre, puis publie message_poste ciblé sur toutes les sessions connectées, par la clé d'enveloppe id.

  6. Retour en message_poste

    Le canal serveur traduit l'id en sockets et envoie la trame, sans les clés d'enveloppe. Le canal client la publie, le broker client la valide, ecran_fil l'affiche.

Ce que fwtozza ne régit pas

À l'intérieur d'un composant, on programme normalement : POO classique, une bibliothèque ESM, un rendu à la main. fwtozza ne régit que les frontières entre composants. Une liste et sa zone de saisie, une table et son formulaire, vivent dans le même composant si elles partagent le même état et se déploient ensemble.

Granularité : pas un composant par action, pas un message par verbe

On découpe par fonction et/ou déploiement, jamais par géométrie d'écran. Un agrégat de une à trois tables liées fait un composant serveur. Une zone fonctionnelle fait un composant client. Une capacité fait un message avec oneOf (gerer_clients.read, .create, .update, .delete) plutôt qu'une nuée de contrats-verbes. Avant de rendre une conception, comptez vos composants et vos messages : trop nombreux, vous avez sur-découpé. La méthode complète.