Saltar al contenido principal

Alertas de relaciones entre entidades

Las alertas de relaciones son la versión general del disparador de reposición de e-commerce, pero para cualquier entidad personalizada: asientos, vuelos, clases, espectáculos, citas o inventario B2B. La idea es sencilla:

Cuando cambia un registro de un catálogo, notifica a todos los contactos vinculados a ese registro mediante una segunda entidad relacionada.

Declaras una entidad principal - el catálogo cuyos registros cambian (por ejemplo, concert_tickets o series) - y eliges cómo se encuentra la audiencia: una lista de suscripción relacionada (una entidad de lista de espera / «seguir») o las personas que realizaron un evento relevante (vieron / consultaron). Consulta Dos formas de definir la audiencia más abajo.

Cuando cambia el campo vigilado de un registro principal, Joryio resuelve esa audiencia y emite un evento por usuario que puedes usar como disparador de entrada de un recorrido o campaña, deduplicado por persona para que valores inestables no envíen spam a nadie.

¿Por qué dos entidades?​

La función integrada de reposición de productos requiere un clic porque el catálogo de productos tiene una estructura conocida (un campo de stock y una lista de suscriptores). Las entidades personalizadas son libres: Joryio no puede adivinar qué campo significa «disponible» ni qué entidad contiene la lista de espera, por lo que lo declaras una vez en los ajustes de la entidad principal.

For most e-commerce stores the product catalog is still the easy path. Reach for relationship alerts when your catalog isn't products, or when the audience is an explicit list rather than inferred browsing intent.

Dos formas de definir la audiencia​

Antes de configurar, la decisión clave es quién recibe la notificación:

  • Comportamiento (audienceSource: "event"): las personas que realizaron un evento de intención (por ejemplo, Watched Episode, Viewed Flight) que hace referencia al registro, dentro de una ventana retrospectiva. No hay registros de seguimiento/lista de espera que mantener: la audiencia es el comportamiento. Refleja cómo la reposición de productos crea su audiencia a partir de eventos de navegación. Es ideal para «notificar a todos los que vieron/consultaron».
  • Explícita (audienceSource: "child_entity", predeterminado): las filas de una entidad de suscripción relacionada (una lista de espera «avísame» o una lista «seguir este espectáculo»). Es ideal cuando las personas se suscriben deliberadamente, independientemente de cualquier comportamiento.

No necesitas una entidad de seguimiento para el caso VOD; consulta el Ejemplo 2.

«Avísame» como evento frente a entidad de lista de espera​

Una pregunta habitual: si un toque «Avísame» emite un evento (Notify Me con un product_id), ¿sigues necesitando una entidad de lista de espera? Normalmente no: dirige a ella el modo de evento (intentEvent: "Notify Me", intentRefProperty: "product_id") y ya está.

Lo único que te hace volver a una entidad secundaria es la durabilidad. Una audiencia de eventos está limitada por dos factores:

  • la ventana retrospectiva (intentLookbackDays), y
  • la retención de eventos: el TTL de retención de datos del espacio de trabajo finalmente elimina el evento y, una vez eliminado, el modo de evento ya no puede verlo.

El momento de reposición es abierto: un artículo puede volver la semana siguiente o dentro de ocho meses. Si el evento «avísame» caducó cuando se repone, el modo de evento no alcanza a esa persona; una fila de lista de espera persiste hasta que la elimines. Por tanto:

  • Horizonte corto y predecible (episodios nuevos, reposiciones rápidas) → modo de evento, sin entidad.
  • Horizonte abierto, o si quieres una lista gestionable de «notificar una vez y eliminar» → entidad secundaria de lista de espera.

Configuración​

Se configura en la entidad principal. En la app: Entidades -> editar la entidad -> Ajustes -> Avisar a las personas vinculadas a un registro - activa el interruptor y la sección muestra el campo a vigilar, qué cuenta como cambio, el evento a emitir, el enfriamiento, quién recibe el aviso y la regla "omitir a quienes ya actuaron". Cada control corresponde uno a uno a una clave de settings.relationshipAlert, que es lo que configuran la API y el asistente:

CampoSignificadoEjemplo
enabledActiva la alertatrue
triggerModeQué cuenta como activación en field (ver abajo)"restock"
fieldCampo principal cuya transición activa la alerta"available"
eventNameEvento por usuario que se emitirá"back_in_stock"
cooldownDaysVentana de supresión por (persona, registro) (predeterminado: 7)7
audienceSource"child_entity" (predeterminado) o "event""event"
childEntity(modo secundario) nombre interno de la entidad de lista de espera/seguimiento"ticket_waitlist"
childRefField(modo secundario) campo en las filas secundarias que contiene el ID del registro principal"ticketId"
intentEvent(modo de evento) evento de intención cuya audiencia se notificará"Watched Episode"
intentRefProperty(modo de evento) propiedad del evento que contiene el ID del registro principal"series_id"
intentLookbackDays(modo de evento) hasta qué punto mirar atrás (predeterminado: 90)90
minDropPct(modo decrease) caída mínima, en porcentaje del valor anterior, para que se active (predeterminado: 5)5

Modos de disparador

  • restock: un número pasa de ≤ 0 a > 0 (vuelve a haber existencias). Predeterminado.
  • increase: un número aumenta (por ejemplo, un recuento de episodios de 8 → 9).
  • changed: un valor cambia a un valor nuevo no vacío (por ejemplo, un «ID de episodio más reciente»).
  • decrease: un número positivo baja al menos minDropPct por ciento hasta otro número positivo (por ejemplo, una tarifa de hotel de 200 → 180). Es el equivalente para catálogos personalizados de la bajada de precio integrada - consulta el Ejemplo 3.

En el modo child-entity, la entidad secundaria debe declarar un enlace de usuario (qué campo se asigna a un contacto, por ID de usuario / ID externo / email / teléfono / atributo): así es como cada fila se resuelve en una persona. En el modo event, el user_id del evento de intención es el contacto. Un valor anterior desconocido nunca activa nada (en los modos numéricos), por lo que las primeras cargas no generan alertas falsas.


Ejemplo 1: entradas de concierto de nuevo disponibles​

Objetivo: un espectáculo se agota; cuando vuelven a liberarse entradas, notifica a todos los que pidieron que se les avisara.

  1. Entidad principal concert_tickets con un campo numérico available.

  2. Entidad secundaria ticket_waitlist con los campos ticketId (el espectáculo/registro al que hace referencia) y email. Configura su enlace de usuario en email.

  3. En concert_tickets, configura:

    {
    "relationshipAlert": {
    "enabled": true,
    "triggerMode": "restock",
    "field": "available",
    "childEntity": "ticket_waitlist",
    "childRefField": "ticketId",
    "eventName": "back_in_stock",
    "cooldownDays": 30
    }
    }
  4. Cuando alguien toca «Avísame», tu app/sitio añade una fila a ticket_waitlist: { ticketId: "SHOW-A", email: "[email protected]" }.

  5. Cuando available de concert_tickets/SHOW-A pasa de 0 → 50, Joryio emite un evento back_in_stock para cada contacto en lista de espera.

Crea un recorrido de un paso (o una campaña activada) cuya entrada sea back_in_stock. Personalízalo con los propios campos del registro, que viajan en el evento:

{{ event.name }} tickets are back! Grab yours before they sell out again.

El evento también incluye event.record_id, event.new_value (el nuevo stock) y cualquier campo escalar del registro.


Ejemplo 2: episodio nuevo de una serie que alguien ve (VOD / estilo Netflix)​

Objetivo: cuando se publica un episodio nuevo de una serie, avisa a todos los que han estado viendo esa serie.

¿Necesito una entidad «seguir» o puedo usar un evento de visualización? Puedes usar el evento de visualización, y para VOD es la opción natural. Ya emites un evento Watched Episode (o watch_series) cuando alguien reproduce un episodio; dirige la alerta a ese evento y Joryio notificará a todos los que vieron la serie recientemente. No hay registros de seguimiento que crear ni mantener. Usa una entidad de seguimiento solo si quieres una lista explícita de suscripción «seguir este espectáculo» independiente de la visualización.

¿Es igual que una reposición o es diferente? Aquí la parte de audiencia usa comportamiento en vez de una lista de espera (esa es la opción audienceSource: "event"), y el disparador también difiere: un episodio nuevo no es un cambio de stock 0 → >0, es un recuento de episodios que aumenta (o un ID de «último episodio» que cambia). Es el mismo motor, con dos controles distintos.

Lo que necesitas: una sola entidad:

  1. Entidad principal series con:

    • un campo de presentación como title;
    • un campo numérico episodeCount (o una cadena latestEpisodeId);
    • ninguna entidad secundaria.
  2. En series, configura:

    {
    "relationshipAlert": {
    "enabled": true,
    "triggerMode": "increase",
    "field": "episodeCount",
    "audienceSource": "event",
    "intentEvent": "Watched Episode",
    "intentRefProperty": "series_id",
    "intentLookbackDays": 90,
    "eventName": "new_episode",
    "cooldownDays": 1
    }
    }

    (Prefer "triggerMode": "changed" with "field": "latestEpisodeId" if you track the newest episode by id rather than a running count.)

  3. La conexión es la propiedad del evento. Tu reproductor ya envía, en cada reproducción, algo como:

    { "event": "Watched Episode", "series_id": "S-42", "episode": 12 }

    intentRefProperty: "series_id" es lo que vincula una visualización con el registro series: debe coincidir con el ID del registro o el valor de clave principal (S-42).

  4. Cómo activar: cuando la ingesta de catálogo aumenta episodeCount de series/S-42 de 8 → 9 (una actualización normal de registro), Joryio consulta quién realizó Watched Episode con series_id = S-42 durante los últimos 90 días y emite un evento new_episode para cada uno.

  5. Crea un recorrido/campaña cuya entrada sea new_episode:

    Ya está disponible un episodio nuevo de {{ event.name }}. Retoma donde lo dejaste →

If you prefer an explicit follow list instead of watch behavior, keep triggerMode: "increase" but use the child-entity audience: add a series_follows entity (seriesId, userId, User Link → userId), set audienceSource: "child_entity", childEntity: "series_follows", childRefField: "seriesId", and add a follow row when someone taps Follow.

Reposición frente a episodio nuevo de un vistazo

Reposición de conciertoEpisodio nuevo (VOD)
Entidades necesariasprincipal + lista de espera secundariasolo la principal
Audienciafilas de ticket_waitlist (suscripción)evento Watched Episode (comportamiento)
audienceSourcechild_entityevent
Campo vigiladoavailable (stock)episodeCount / latestEpisodeId
triggerModerestock (0 → >0)increase / changed
Evento emitidoback_in_stocknew_episode

Ejemplo 3: «El precio de tus fechas acaba de bajar» (tarifas de hotel)​

Objetivo: un huésped buscó una estancia y guardó las fechas; cuando la tarifa de esa habitación y esas fechas baja, avísale - igual que la bajada de precio integrada lo hace con los productos de Shopify y WooCommerce, pero para un catálogo que Joryio no sincroniza.

  1. Entidad principal hotel_rates con una clave primaria de negocio rateId (una fila por tipo de habitación y rango de fechas), un campo de visualización hotel y un campo numérico rate.

  2. Audiencia: una entidad secundaria saved_searches (rateId, email, enlace de usuario → email) que se rellena cuando el huésped guarda las fechas, o el modo de evento sobre el evento Rate Viewed que tu web de reservas ya envía con un rate_id.

  3. En hotel_rates, configura:

    {
    "relationshipAlert": {
    "enabled": true,
    "triggerMode": "decrease",
    "minDropPct": 5,
    "field": "rate",
    "childEntity": "saved_searches",
    "childRefField": "rateId",
    "eventName": "rate_drop",
    "cooldownDays": 3,
    "excludeEvent": "Booking Completed",
    "excludeRefProperty": "rate_id"
    }
    }
  4. Cuando tu feed de tarifas actualiza hotel_rates/R-1 rate 200 → 180 (una bajada del 10 %, por encima del umbral del 5 %), Joryio emite un evento rate_drop para cada huésped vinculado a esa tarifa - menos quienes ya la reservaron (excludeEvent). Una actualización 200 → 195 (2,5 %) no se activa; tampoco una primera tarifa, una tarifa que sube ni una que pasa a 0 (eso es un agotado, no una oferta).

  5. Crea un recorrido que entre por rate_drop. Además de los campos del registro, el evento lleva el par de valores con el que se midió la bajada:

    {{ event.hotel }} para tus fechas ahora cuesta {{ event.new_value }} - un {{ event.drop_pct }} % menos que {{ event.old_value }}.

Propiedades de una activación decrease

PropiedadSignificado
old_valueValor del campo antes de la actualización
new_valueValor del campo después de la actualización
drop_pctLa bajada como porcentaje de old_value, redondeada a 1 decimal (10 para 200 → 180)

drop_pct tiene el mismo nombre y significado que en el evento price_drop integrado, así que una condición de recorrido escrita para uno vale para el otro. El par de valores es old_value / new_value en vez de old_price / new_price porque aquí el campo vigilado puede ser cualquier número: una tarifa, una comisión, un billete, un tiempo de espera.

Una nueva bajada a un valor distinto (180 → 160) es otra transición y vuelve a avisar tras el periodo de enfriamiento; el mismo valor llegando otra vez no lo hace.


Excluir a las personas que ya actuaron​

Si envías algo de tiempo después del lanzamiento, probablemente no quieras insistir a las personas que ya vieron el episodio nuevo (o ya compraron el artículo repuesto). Hay dos capas, y a menudo usarás ambas:

1. Omitirlas al activar: excludeEvent​

La alerta puede eliminar de la audiencia a cualquiera que ya haya realizado un evento para el valor nuevo de esta transición. Para el ejemplo VOD, añade a la configuración:

{
"excludeEvent": "Watched Episode",
"excludeRefProperty": "series_id",
"excludeValueProperty": "episode",
"excludeLookbackDays": 30
}

Ahora, cuando se publica el episodio 9, Joryio notifica a quienes vieron la serie, pero excluye a cualquiera que ya vio el episodio 9 (series_id = esta serie y episode = el valor nuevo). excludeValueProperty lo vincula al episodio nuevo específico. Para que coincida, el valor nuevo del campo debe coincidir con el ID que lleva tu evento de visualización (esto es más limpio con triggerMode: "changed"

  • latestEpisodeId, o cuando los números de episodio son iguales al recuento). También sirve para reposición: configura excludeEvent como tu evento de compra para omitir compradores recientes.

2. Volver a comprobar al enviar: la respuesta exacta para envíos retrasados​

La exclusión al activar solo sabe quién vio algo hasta el momento en que se activa la alerta. Si deliberadamente esperas 2 días antes de enviar, las personas verán contenido durante esos dos días, y solo una comprobación al enviar puede detectarlas. Hazlo en el recorrido:

  1. Disparador de entrada: new_episode.
  2. Espera 2 días.
  3. Condición / bifurcación de comportamiento: NO ha realizado Watched Episode donde episode = {{ trigger.new_value }} durante los últimos 2 días → solo esta rama continúa al envío.

Esto vuelve a evaluar a cada persona justo antes de enviar, de modo que cualquiera que se haya puesto al día durante la espera queda excluida. Usa excludeEvent (capa 1) para mantener ajustada la audiencia inicial y la condición del recorrido (capa 2) para hacer exacto un envío retrasado.

Usar el evento de alerta​

Independientemente de su nombre, eventName se comporta como cualquier otro evento de Joryio:

  • Aparece en el selector de eventos como disparador de entrada de recorrido/campaña.
  • Sus propiedades (record_id, new_value, field, además de los campos escalares del registro y una etiqueta name - y, en una alerta decrease, old_value y drop_pct) están disponibles como event.* en Liquid.
  • Los envíos siguen respetando el consentimiento, la supresión y las horas de silencio como cualquier otro envío de canal.

Cómo se activa internamente​

La transición se detecta en la ruta de actualización de la entidad y se distribuye fuera de la ruta crítica, por lo que una audiencia lenta nunca bloquea la escritura del registro. Las notificaciones se deduplican por (contacto, registro) durante cooldownDays, y una fila secundaria solo cuenta una vez incluso si varias filas se resuelven en el mismo contacto.

Importaciones masivas​

Las importaciones masivas de registros no activan alertas de forma predeterminada, así que una primera carga nunca avisa a todo el mundo. Actívalas por importación enviando triggerAlerts: true al endpoint masivo. Cuando está activado y la entidad tiene una clave principal de negocio, la importación hace upsert y diferencia: se actualizan los registros que ya existen y sus transiciones se activan (por ejemplo, un feed nocturno de stock o episodeCount), mientras que las filas nuevas solo activan alertas de modo changed (los modos numéricos necesitan un valor anterior desde el que cambiar).

Puesta en marcha​

Tres vías, y todas escriben la misma configuración relationshipAlert:

  • En el constructor - abre la entidad principal (Entidades -> editar), baja hasta Ajustes -> Avisar a las personas vinculadas a un registro, activa el interruptor y rellena el campo, el modo, el evento, el enfriamiento, la audiencia y la regla de omisión. El constructor solo ofrece campos numéricos para los modos numéricos, muestra el porcentaje solo en decrease y se niega a guardar un porcentaje fuera de rango. La entidad secundaria de lista de espera sigue necesitando su Vínculo de contacto en sus propios ajustes.
  • Mediante la API - envía settings.relationshipAlert en la entidad con las claves de la tabla anterior. Aplican las mismas reglas: un triggerMode conocido y un minDropPct entre 0 y 100.
  • Con el asistente de IA - pídelo todo en una sola solicitud: crea la entidad secundaria de seguimiento/lista de espera, configura la alerta y construye el recorrido de notificación.

Desactivar el aviso en el constructor conserva la configuración con enabled: false, de modo que al reactivarlo más tarde todo sigue como estaba.