Avisa a las pantallas abiertas que algo cambió, para que vuelvan a consultar la API. Por el canal nunca viaja un dato del negocio: solo ids y el tipo de aviso. La API decide qué puede ver cada persona cuando el front vuelve a consultar (ADR-0024 y ADR-0057).
Endpoints
Exigen sesión completa: un token de ingreso a medias (falta el MFA) responde 401.
| Método | Ruta | Respuesta |
|---|---|---|
GET | /api/v1/realtime | { key, path }: la clave pública de Reverb y la ruta del gateway (/ws). El secreto nunca sale |
POST | /api/v1/broadcasting/auth | Firma las suscripciones de una pestaña en una sola petición: recibe socket_id ("123.456") y channels (hasta 10, private-…) y responde { canal: { auth } }, con null en los canales que la persona no puede escuchar |
Las firmas van juntas porque cada petición a PHP cuesta, y al abrir la app se piden todas a la vez. Con una por canal, la carga de cada pantalla sumaba hasta cuatro peticiones y, con la API limitada a una CPU en Docker, eso alcanzaba para que otras respuestas superaran su tiempo de espera.
Canales
| Canal | Quién lo escucha | Qué recibe |
|---|---|---|
incidents.all | incidents.view.any | Cambios de todos los incidentes |
incidents.unassigned | incidents.view.unassigned | Cambios de incidentes que estaban o quedan sin asignar |
users.{ULID} | Solo esa persona | Cambios de lo que creó o tiene asignado, “te asignaron”, “tus notificaciones cambiaron” y “tu sesión cambió” |
La regla es Channels::allows (dominio), con los permisos efectivos de la persona. Channels::forIncident decide a qué canales va cada cambio:
- Siempre al general.
- Al de sin asignar, si lo estaba antes o queda así. Un incidente recién creado solo cuenta por cómo quedó.
- Al canal personal de quien lo creó y de quien estaba o queda asignado, sin repetir.
Avisos
| Nombre | Canal | Contenido | Cuándo |
|---|---|---|---|
incident.changed | Los de forIncident | { id, change } (created, updated, deleted, restored) | Cada IncidentChanged |
incident.commented | Los de forIncident (creador y asignado actuales) | { id, change } (added, removed) | Cada IncidentCommented: llegó o se borró un mensaje de la conversación |
incident.assigned | users.{asignado} | { id } | El incidente quedó asignado a otra persona que no es quien hizo el cambio |
notifications.changed | users.{persona} | {} | Llegó un aviso nuevo al centro de notificaciones, o la persona marcó avisos como leídos en otra pestaña |
session.changed | users.{persona} | {} | Cambio de rol, de permisos, de datos o de estado; restablecer el MFA o el acceso; editar su rol; cambiar o recuperar la contraseña |
- Por la cola y tras confirmar (
Signal,afterCommit): no frenan la respuesta y nunca salen de un cambio que al final se deshizo. - Sin el aviso propio:
incident.changedeincident.commentedsalen contoOthers(). La pestaña que hizo el cambio manda suX-Socket-IDy no lo recibe.
De dónde salen
- Incidentes: el repositorio emite
IncidentChangedcon el id, el ULID, qué pasó, quién lo creó y a quién estaba y queda asignado. Lo escuchan la caché del dashboard yBroadcastIncidentChange. - Notificaciones: el módulo Notifications llama a su puerto
NotificationSignalsal crear avisos o marcarlos como leídos. Lo implementaBroadcastNotificationSignals. - Sesión: los casos de uso de Users y de Auth llaman al puerto compartido
SessionSignals. Lo implementaBroadcastSessionSignals, que traduce los ids a canales personales.
Configuración
- Reverb corre en su propio contenedor y la app le habla por la red interna (
http://reverb:8080). Detalles de operación en Tiempo real. - Pruebas:
BROADCAST_CONNECTION=nully la colasync. Las pruebas revisan los avisos conEvent::fake. Para la firma de canales cambian areverbcon una clave de prueba: Reverb firma sin necesidad del servidor.
Capas
| Capa | Pieza | Qué hace |
|---|---|---|
| Domain | Channels | Nombres de canal, quién escucha cada uno y a cuáles va un cambio |
| Shared/Application | Ports/SessionSignals | “La sesión de estas personas cambió”; lo usan Users y Auth |
| Infrastructure | Events/Signal (+ IncidentSignal, CommentSignal, AssignedSignal, NotificationsSignal, SessionSignal) | Los avisos que salen por Reverb |
| Infrastructure | BroadcastIncidentChange, BroadcastIncidentComment, BroadcastNotificationSignals, BroadcastSessionSignals | Traducen eventos y ids a avisos y canales |
| Infrastructure | RealtimeServiceProvider | Autorización de los canales, oyente e implementación del puerto |
| Http | RealtimeController, routes.php | Configuración de conexión y firma de suscripciones (una copia de la petición por canal para Broadcast::auth) |
| Http | Requests/ChannelAuthRequest, Rules/SocketId | Valida el id de la conexión y la lista de canales |
Dónde está en el código
backend/app/Modules/Realtime/backend/app/Modules/Shared/Application/Ports/SessionSignals.phpbackend/app/Modules/Incidents/Application/Events/IncidentChanged.php- Configuración:
config/reverb.phpyconfig/broadcasting.php - Pruebas:
tests/Feature/Realtime/RealtimeTest.phpytests/Unit/Realtime/ChannelsTest.php