Saltar al contenido principal

Notificaciones — Referencia técnica

← Volver a Notificaciones

Dónde vive esto

Backend

Frontend

Checklist de implementación técnica

  • myNotifications / markNotificationAsRead / markAllNotificationsAsRead — resolvers conectados en notification.resolver.js; NotificationsPanel.tsx consulta, muestra y marca los elementos como leídos
  • firebase.service.js / fachada push-notification/ / notification-queue.service.js — implementan por completo la entrega de push del lado del servidor; WebPushRegistrar.tsx (montado una vez para los usuarios autenticados, junto a UsageHeartbeat) ahora llama a registerDeviceToken con platform: 'web' cada vez que initWebPush() resuelve un token, así que el push ahora sí se entrega al cliente web una vez que existe la configuración web de Firebase (antes el frontend nunca llamaba a esta mutation)
  • notificationSettings / updateNotificationSettings / resetNotificationSettings — resolvers conectados en user-notifications.resolver.js; NotificationsSettingsPage.tsx consulta y modifica notificationSettings (canales de email/push/SMS) directamente, y por separado consulta/modifica un subconjunto pauseAll/quietHoursEnabled/messagesOnlyMode de extendedNotificationSettings para sus interruptores del panel principal — llamadas GraphQL reales, no interruptores estáticos
  • unreadNotificationsCount / subscription notificationAddedNotificationsButton.tsx y NotificationsPanel.tsx se suscriben a notificationAdded y recargan el contador/la lista con cada evento, lo que reemplaza el polling anterior de 30 segundos por actualizaciones impulsadas por push

Tipos de notificación

El enum ha crecido mucho más allá del conjunto social original para cubrir eventos de comercio, moderación y seguridad de cuenta:

enum NotificationType {
like # Reaction on your post
comment # Comment on your post
follow # New follower
follow_request # Someone requested to follow you (private account)
mention # Mentioned in a comment or message
tag # Tagged in a post
message # New direct message
message_purchase # Someone bought a paid message
post # Post from someone you follow
post_purchase # Someone bought a paid post
repost # Your post was shared
story_like # Reaction on your story
reaction # Reaction on your story (alt path)
subscription # New subscription to your profile
subscription_renewal_reminder # Upcoming subscription renewal
conversation_subscription # New paid-chat subscription
tip # You received a tip
cashout # Cashout status update
product_purchase # Someone bought your product
order_shipped # Order shipped
order_canceled # Order canceled
dispute_opened # Payment dispute opened
dispute_resolved # Payment dispute resolved
identity_verification_approved # ID verification approved
identity_verification_rejected # ID verification rejected
referral_bonus # Referral bonus earned
collaboration_invite # Invited to collaborate on a post
collaboration_accepted # Collaboration invite accepted
collaboration_rejected # Collaboration invite declined
collaboration_removed # Removed from a collaboration
security_issue # Security alert
system # System notification
system_alert # System notification (alt path)
new_report # New report filed (moderation)
moderation_action # Account moderation action taken
}

DEFAULT_PUSH_TITLES en notification.manager.js mapea cada tipo a su título de notificación push. Los tipos sociales en GROUPABLE_PUSH_TYPES (like, comment, follow, follow_request, repost, story_like, reaction, tag) tienen sus ráfagas de push colapsadas en una sola notificación por ventana de 5 minutos; los tipos transaccionales/de mensajes/de seguridad nunca se agrupan.

Modelo Notification

CampoDescripción
notificationTypeTipo (ver enum)
actorId / actorQuién generó la notificación
entityType / entityIdContenido relacionado
messageTexto de la notificación
isRead / readAtEstado de lectura
groupKey / groupCountAgrupación (p. ej. "5 me gusta")
metadataDatos adicionales (JSON)

Queries

myNotifications devuelve la lista de notificaciones del usuario actual, de más reciente a más antigua. Las notificaciones con el mismo groupKey se agrupan — groupCount indica cuántos eventos se colapsaron en un solo elemento (p. ej. "Alice, Bob y otras 3 personas reaccionaron a tu publicación"). Cada elemento también resuelve un campo post (miniatura para notificaciones relacionadas con publicaciones) y un campo actor, ambos resueltos bajo demanda si no se cargaron de forma anticipada.

notification(id) obtiene una sola notificación por ID (autenticado, con verificación de propiedad en el manager).

unreadNotificationsCount es un contador económico — llámalo al montar la app; después el frontend lo mantiene actualizado mediante la subscription notificationAdded en lugar de polling.

notificationSettings devuelve el estado de los interruptores por canal del usuario — útil para renderizar la UI de configuración.

query MyNotifications($limit: Int, $offset: Int) {
myNotifications(limit: $limit, offset: $offset) {
id notificationType message isRead createdAt
actor { username profilePicture }
entityType entityId
groupKey groupCount
post { id media { thumbnailUrl mediaUrl } }
}
}

query UnreadCount { unreadNotificationsCount }

query NotificationSettings {
notificationSettings {
emailNotifications pushNotifications smsNotifications
likesNotifications commentsNotifications followsNotifications
mentionsNotifications messagesNotifications postsNotifications
marketingNotifications securityNotifications
}
}

Mutations

markNotificationAsRead marca un solo elemento como leído y actualiza readAt. markAllNotificationsAsRead es la versión masiva — llámala cuando el usuario abre el panel de notificaciones.

deleteNotification elimina permanentemente un elemento. deleteAllNotifications borra todo el historial.

createNotification crea una notificación para un userId arbitrario — pensada para uso de sistema/administración, no está expuesta en la UI normal.

updateNotificationSettings guarda los interruptores por canal. resetNotificationSettings revierte todos los interruptores a los valores predeterminados de la plataforma.

mutation MarkRead($notificationId: ID!) { markNotificationAsRead(notificationId: $notificationId) }
mutation MarkAllRead { markAllNotificationsAsRead }
mutation DeleteNotification($id: ID!) { deleteNotification(notificationId: $id) }
mutation DeleteAllNotifications { deleteAllNotifications }

mutation UpdateNotificationSettings($input: NotificationSettingsInput!) {
updateNotificationSettings(input: $input) { success }
}

mutation ResetNotificationSettings { resetNotificationSettings }

Subscription

notificationAdded(userId: ID!) se dispara para el destinatario cada vez que se crea una nueva notificación para él. NotificationsButton.tsx y NotificationsPanel.tsx se suscriben a ella (limitada al propio ID del usuario que inició sesión) y recargan el contador de no leídas / la lista con cada evento — esto reemplazó el intervalo de polling anterior de 30 segundos.

subscription OnNotificationAdded($userId: ID!) {
notificationAdded(userId: $userId) { id }
}

Configuración por canal

Cada canal se activa o desactiva de forma independiente:

ConfiguraciónDescripción
emailNotificationsEntrega por correo electrónico
pushNotificationsEntrega push por FCM
smsNotificationsEntrega por SMS
likesNotificationsReacciones a publicaciones
commentsNotificationsComentarios en publicaciones
followsNotificationsNuevos seguidores
mentionsNotificationsMenciones en contenido
messagesNotificationsMensajes directos
postsNotificationsPublicaciones de usuarios seguidos
marketingNotificationsNoticias y novedades de la plataforma
securityNotificationsAlertas de seguridad

Notificaciones push (FCM)

El backend envía notificaciones push mediante Firebase Cloud Messaging, a través de una fachada independiente del proveedor (services/push-notification/) en la que delegan tanto apns.service.js como services/notification/notification.service.js:

  1. Al iniciar sesión (web) o al abrir la app (iOS), el frontend registra el token del dispositivo (registerDeviceToken) — en web esto lo hace WebPushRegistrar.tsx, condicionado a la configuración web de Firebase
  2. notification.worker.js se ejecuta como un job en segundo plano de BullMQ (concurrencia 10, hasta 100/seg) para despachar los push
  3. El backend usa el Firebase Admin SDK, inicializado en firebase.service.js a partir de las variables de entorno FIREBASE_PROJECT_ID / FIREBASE_PRIVATE_KEY / FIREBASE_CLIENT_EMAIL
  4. PUSH_NOTIFICATION_PROVIDER (por defecto firebase) selecciona el proveedor de entrega en la fachada; DISABLE_PUSH_NOTIFICATIONS corta en seco todos los envíos y los reemplaza por respuestas simuladas (usado en dev/test)

Para iOS, el push VoIP de llamadas entrantes se maneja por separado mediante APNs real (@parse/node-apn en voip-push.service.js, configurado con APNS_PRIVATE_KEY / APNS_KEY_ID / APNS_TEAM_ID / APNS_BUNDLE_ID) en lugar de pasar por la fachada de FCM — ver registerVoIPToken.

Configuración extendida

extendedNotificationSettings / updateExtendedNotificationSettings (graphql/types/extended-notification-settings.type.js + resolver) es una superficie separada y mucho más amplia, construida encima de los canales base descritos arriba — el detalle completo vive en Configuración → Notificaciones, ya que se construyó como parte del trabajo de la funcionalidad de Configuración y no de esta. Respaldada por notification-settings.manager.js, que ya tenía muchas más claves internas de las que se llegaron a exponer a través del tipo base NotificationSettings — la mayoría de los campos extendidos son simplemente estado preexistente del manager recién expuesto, no lógica de negocio nueva.