Vai al contenuto

Tempo reale (WebSocket)

Il WebSocket della piattaforma - il ticket monouso, il sottoprotocollo memberfy-realtime, le stanze automatiche e quelle richieste, gli avvisi invalidate, i limiti e i codici di chiusura.

L'app riceve i cambiamenti subito tramite un WebSocket: la campanella, la chat, l'"Online adesso", chi c'è in ogni schermata, il banner dell'evento in diretta, i numeri delle campagne. Qualsiasi membro della community, di qualsiasi ruolo, apre il socket, con la chat attiva o disattivata.

Aprire la connessione

  1. Chiedi un ticket con POST /api/realtime/ticket, con il token e l'X-CommunityId (vedi Autenticazione e X-CommunityId). Il ticket è monouso, vale 60 secondi ed è legato alla persona, alla community e alla sessione.
  2. Apri wss://<api>/api/realtime/socket (il data.path) passando il ticket come secondo sottoprotocollo, dopo memberfy-realtime (il data.protocols). Il server risponde con memberfy-realtime.
const { data } = await api.post('/api/realtime/ticket'); // con Authorization e X-CommunityId
const ws = new WebSocket(`wss://api.memberfy.net${data.path}`, data.protocols);

Il ticket non va mai nell'URL (nella query viene ignorato). Senza un ticket valido, la connessione viene rifiutata prima di diventare WebSocket (401). Cambiare community chiude il socket: chiedi un altro ticket. Senza il servizio di tempo reale, il ticket restituisce 503, e l'app continua a leggere tramite le rotte.

POST /api/chat/ticket e /api/chat/socket continuano a funzionare come alias di questi per un deploy e poi spariscono: usa i nuovi.

Stanze

Ogni connessione entra già in tre stanze:

StanzaChi
meLa persona stessa
communityTutti nella community
staffSolo il team (proprietario, amministratore, moderatore e finanza)

Le altre le chiede il client, con la stessa regola del GET corrispondente, sempre in questa community:

StanzaChi entra
space:<id>Chi può aprire lo spazio
item:event:<id>Chi può aprire l'evento
item:post:<id>Chi può aprire il post
{ "type": "subscribe", "rooms": ["space:5b0e7c1a-…", "item:event:9d2f…"] }
{ "type": "unsubscribe", "rooms": ["space:5b0e7c1a-…"] }

Ci sono anche stanze per gli editor, solo per i ruoli che possono salvare lì: item:course:<id>, item:form:<id> (il team e chi gestisce il modulo; un membro quando è pubblicato e apre lo spazio), item:campaign:<id>, item:email:<id> (e-mail della libreria), item:workflow:<id>, item:survey:<id> (proprietario e amministratore), item:certificateTemplate:<id> (chi emette certificati nello spazio), item:emailOverride:<emailKey> (e-mail predefinita, proprietario e amministratore). E le stanze di area, una per schermata di sezione: area:home (tutti), area:members, area:campaigns, area:emails, area:workflows (team), area:moderation (proprietario, amministratore e moderatore), area:analytics, area:dashboard, area:settings (proprietario e amministratore) e area:finance (proprietario, amministratore e finanza).

Al massimo 20 stanze per connessione (quelle automatiche non contano). La risposta è subscribed con le stanze accettate e un subscribe.denied per stanza rifiutata, senza motivo. Quando l'accesso della persona cambia (è uscita, nuovo ruolo, gruppo, accesso allo spazio), il server rivaluta le stanze, manda subscribe.denied per quelle perse e poi access.changed.

Avvisi di cambiamento (invalidate)

{ "type": "invalidate", "room": "community", "topic": "event.live", "ids": ["9d2f…"], "at": "2026-10-23T14:05:00.000Z" }

L'avviso porta solo gli id e l'argomento, mai titolo, testo, importo o nome: quando lo ricevi, rifai il GET di ciò che è sullo schermo tramite le rotte di sempre.

ArgomentoStanzaQuando
event.livecommunity, space:<id>, item:event:<id>Un evento ha iniziato o finito la trasmissione
eventscommunity, space:<id>, item:event:<id>Un evento è stato creato, modificato o rimosso
analytics.onlinestaff (proprietario e amministratore)L'"Online adesso" è cambiato (al massimo 1 volta ogni 5 secondi)
campaigns.statsstaffUn invio di campagna è terminato
menu.changedcommunityIl menu è cambiato: sezione o spazio creato, modificato (nome, icona, indirizzo, sezione, accesso, visibilità), rimosso o riordinato. Senza ids e senza nessun dato del menu: ogni persona rifà il GET /api/sections con i propri permessi. Modifiche in sequenza diventano un solo avviso, entro 1 secondo

Gli avvisi degli eventi arrivano solo a chi vede quello spazio; un evento privato o in moderazione, solo al team.

Chi c'è qui

La presenza di area (i volti in cima a ogni schermata, vedi Chi c'è qui e modifica in team) usa le stesse stanze.

{ "type": "presence.join", "room": "area:campaigns", "editing": false }
{ "type": "presence.leave", "room": "area:campaigns" }
{ "type": "presence.active" }
  • presence.join all'apertura della schermata: la stanza viene valutata come in subscribe (e sottoscritta, se non lo era), al massimo 3 posti per connessione. La risposta è presence.joined (room, editing) seguito da un'istantanea presence, oppure presence.denied (room), senza motivo.
  • presence.leave all'uscita. Non c'è heartbeat: il ping del server mantiene il posto, che sparisce 45 secondi dopo l'ultima risposta; chiudere la connessione lo toglie subito.
  • presence.active quando c'è interazione (tasto, clic, focus), al massimo ogni 10 secondi. Entrare conta come attività.

A ogni cambiamento (al massimo 1 al secondo per stanza), la stanza riceve un'istantanea costruita per ogni connessione:

{
  "type": "presence", "room": "area:campaigns", "area": "area:campaigns",
  "members": [{ "memberId": "…", "name": "Maria", "avatarUrl": "…", "editing": false, "state": "active", "lastActiveAt": "…" }],
  "count": 3, "editingCount": 1, "at": "2026-10-28T14:05:00.000Z"
}
  • Tu non sei mai nella tua lista. members contiene al massimo 5 persone (prima chi modifica ed è attivo, poi gli attivi, poi gli inattivi); count è il totale delle altre persone nella stanza.
  • Chi legge soltanto: nelle stanze di spazio e di elemento, chi non sta modificando lì riceve solo memberId, name, avatarUrl e state, senza editing, lastActiveAt né editingCount, per la privacy di chi modifica. Chi modifica lo stesso elemento e le stanze di area del team ricevono l'istantanea completa.
  • state: "idle": connessa, senza attività da 30 secondi o più. Resta nella lista.
  • Privacy: chi ha disattivato Disponibile a chattare non compare né conta per gli altri, ma vede chi c'è. Un blocco nella chat nasconde le due persone l'una all'altra.
  • Chat della community disattivata: le stanze di area e chi legge soltanto non ricevono nessuno (members vuoto, count 0), team compreso. Solo chi modifica lo stesso elemento continua a vedere gli altri editor; item.saved e il 409 di versione non cambiano.

Modifica e item.saved

In un editor (evento, campagna, e-mail della libreria, workflow, corso, modulo, sondaggio, modello di certificato, e-mail predefinita e le impostazioni, in area:settings), entra con "editing": true. Vale solo per chi può salvare lì (il team e, nel modulo, chi lo gestisce). Chi modifica compare con editing: true agli altri editor della stanza, anche con lo stato della chat disattivato; chi legge solo la pagina non lo sa. editingCount conta solo chi modifica ed è attivo.

A ogni salvataggio, la stanza riceve, per il team e per chi sta modificando:

{ "type": "item.saved", "topic": "item.saved", "room": "item:campaign:<id>", "itemType": "campaign", "itemId": "<id>", "by": { "memberId": "…", "name": "Maria" }, "updatedAt": "<nuova versione>", "at": "…" }

Confronta updatedAt con la versione che hai per ignorare il tuo salvataggio. itemType: event, campaign, email, workflow, course (inclusi moduli e lezioni), form, survey, certificateTemplate, emailOverride (itemId = emailKey) e, nella stanza area:settings (itemId = la community), settings, chatSettings, notificationSettings, messagingSettings (SMS + WhatsApp), creditSettings, businessInformation, payoutSettings.

I salvataggi accettano la versione letta e rispondono 409 quando un altro è arrivato prima: vedi Conflitto di versione.

Altri eventi

Dal server, in JSON { type, data }: ready (con profileId, communityId, chatAvailable, chatStatus (lo stato scelto in chat), chatEnabled, rooms, maxRooms e pingIntervalMs), notification.new, notification.read e notification.removed (la campanella, in ogni community), chat.settings, session.revoked e pong. Gli eventi della chat arrivano solo con la chat attiva; con la chat disattivata, il socket resta in piedi e si fermano solo quelli.

Dal client: subscribe, unsubscribe, presence.join, presence.leave, presence.active, presence.idle ({ "type": "presence.idle", "idle": true } quando la scheda resta inattiva per 10 minuti, false quando torna: la persona risulta Assente finché tutte le sue schede sono inattive), typing (solo con la chat attiva) e ping.

Limiti e codici di chiusura

  • Messaggi fino a 4 KB, niente binario, al massimo 5 al secondo.
  • Il server manda un ping ogni 25 secondi.
  • Per riconnetterti, aspetta un tempo casuale e crescente e chiedi un ticket nuovo.
CodiceCosa significaCosa fare
4004Sessione terminataNon riconnetterti con la stessa sessione
4009Sostituita: la persona ha aperto più di 10 connessioni e si è chiusa la più vecchiaNiente, se è la scheda vecchia
4029Server pienoRiconnettiti più tardi e usa le rotte nel frattempo
1008Troppi messaggiRallenta
1001Server in riavvioRiconnettiti

Correlati