Notificaciones
Endpoints para gestionar notificaciones de usuario y suscripciones push.
Modelos de Datos
Section titled “Modelos de Datos”Los siguientes modelos de Prisma pertenecen al schema notifications:
Notification
Section titled “Notification”model Notification { id String @id @default(cuid()) userProfileId String @map("user_profile_id") notificationTemplateId String? @map("notification_template_id")
type NotificationType title String body String icon String? badge String? image String?
priority NotificationPriority @default(NORMAL) requiresInteraction Boolean @default(false) @map("requires_interaction") silent Boolean @default(false)
status NotificationStatus @default(PENDING) scheduledAt DateTime? @map("scheduled_at") sentAt DateTime? @map("sent_at") deliveredAt DateTime? @map("delivered_at") readAt DateTime? @map("read_at")
data Json? actions Json?
relatedEntityType String? @map("related_entity_type") relatedEntityId String? @map("related_entity_id")
failureReason String? @map("failure_reason") retryCount Int @default(0) @map("retry_count")
expiresAt DateTime? @map("expires_at")
userProfile UserProfile @relation(fields: [userProfileId], references: [id], onDelete: Cascade) notificationTemplate NotificationTemplate? @relation(fields: [notificationTemplateId], references: [id], onDelete: SetNull)
createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at")
@@index([userProfileId, status]) @@index([scheduledAt]) @@index([type]) @@map("notifications") @@schema("notifications")}PushSubscription
Section titled “PushSubscription”model PushSubscription { id String @id @default(cuid()) userProfileId String @map("user_profile_id") endpoint String p256dh String auth String userAgent String? @map("user_agent") deviceName String? @map("device_name") isActive Boolean @default(true) @map("is_active")
userProfile UserProfile @relation(fields: [userProfileId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at")
@@unique([userProfileId, endpoint]) @@map("push_subscriptions") @@schema("notifications")}NotificationTemplate
Section titled “NotificationTemplate”model NotificationTemplate { id String @id @default(cuid()) type NotificationType @unique title String body String icon String? badge String? image String? priority NotificationPriority @default(NORMAL)
actions Json?
requiresInteraction Boolean @default(false) @map("requires_interaction") silent Boolean @default(false) ttl Int? @default(86400)
variables String[]
isActive Boolean @default(true) @map("is_active")
notifications Notification[]
createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at")
@@map("notification_templates") @@schema("notifications")}NotificationType (Enum)
Section titled “NotificationType (Enum)”enum NotificationType { CLASS_REMINDER RESERVATION_CONFIRMED RESERVATION_CANCELLED MEMBERSHIP_EXPIRING PAYMENT_REMINDER ACHIEVEMENT_UNLOCKED STREAK_MILESTONE GOAL_REMINDER FRIEND_ACTIVITY CLASS_CANCELLED TRAINER_ASSIGNED WORKOUT_REMINDER SYSTEM_ANNOUNCEMENT CUSTOM
@@schema("notifications")}NotificationPriority (Enum)
Section titled “NotificationPriority (Enum)”enum NotificationPriority { LOW NORMAL HIGH URGENT
@@schema("notifications")}NotificationStatus (Enum)
Section titled “NotificationStatus (Enum)”enum NotificationStatus { PENDING SENT DELIVERED READ FAILED EXPIRED
@@schema("notifications")}Sistema de Notificaciones
Section titled “Sistema de Notificaciones”El sistema soporta notificaciones in-app y push notifications usando Web Push. Las notificaciones pueden ser programadas, enviadas inmediatamente, o basadas en plantillas.
Endpoints
Section titled “Endpoints”Obtener Notificaciones
Section titled “Obtener Notificaciones”Obtener notificaciones del usuario.
- URL:
/api/v1/notifications - Método:
GET - Autenticación Requerida: Sí
Descripción Interna
Section titled “Descripción Interna”Este endpoint obtiene notificaciones del usuario con filtrado:
-
Filtros disponibles:
type: Tipo de notificaciónstatus: PENDING, SENT, DELIVERED, READ, FAILED, EXPIREDpriority: Prioridad de la notificaciónisRead: ‘true’ o ‘false’ para filtrar leídas/no leídasdateFrom/dateTo: Rango de fechas
-
Incluye:
- userProfile (id, name)
- notificationTemplate si se usó plantilla
-
Ordenamiento dinámico por sortBy/sortOrder
Parámetros de Consulta de Solicitud
Section titled “Parámetros de Consulta de Solicitud”read: Filtrar por status de lecturatype: Filtrar por tipo de notificaciónstatus: Filtrar por statuspage: Número de páginalimit: Resultados por página
Respuesta
Section titled “Respuesta”{ "data": [ { "id": "...", "type": "RESERVATION_CONFIRMED", "title": "Reserva confirmada", "body": "Tu reserva para Yoga ha sido confirmada", "status": "DELIVERED", "readAt": null, "createdAt": "2023-10-27T10:00:00Z" } ], "pagination": {...}}Ejemplo de Cliente Hono
Section titled “Ejemplo de Cliente Hono”import { hcWithType } from '@vitality-gym/api/client'
const client = hcWithType('http://localhost:3000')
const res = await client.api.v1.notifications.$get({ query: { read: 'false' }})Obtener Conteo de No Leídas
Section titled “Obtener Conteo de No Leídas”Obtener conteo de notificaciones no leídas.
- URL:
/api/v1/notifications/unread-count - Método:
GET - Autenticación Requerida: Sí
Descripción Interna
Section titled “Descripción Interna”Este endpoint cuenta notificaciones no leídas:
-
Filtra notificaciones donde:
- userProfileId coincide
- readAt es null
- status no es EXPIRED
-
Retorna solo el conteo
Respuesta
Section titled “Respuesta”{ "data": { "unreadCount": 5 }}Ejemplo de Cliente Hono
Section titled “Ejemplo de Cliente Hono”import { hcWithType } from '@vitality-gym/api/client'
const client = hcWithType('http://localhost:3000')
const res = await client.api.v1.notifications['unread-count'].$get()Marcar Como Leída
Section titled “Marcar Como Leída”Marcar una notificación como leída.
- URL:
/api/v1/notifications/:notificationId/read - Método:
PATCH - Autenticación Requerida: Sí
Descripción Interna
Section titled “Descripción Interna”Este endpoint marca una notificación como leída:
-
Actualiza la notificación:
- status: READ
- readAt: Fecha actual
-
Retorna la notificación actualizada
Ejemplo de Cliente Hono
Section titled “Ejemplo de Cliente Hono”import { hcWithType } from '@vitality-gym/api/client'
const client = hcWithType('http://localhost:3000')
const res = await client.api.v1.notifications[':notificationId'].read.$patch({ param: { notificationId: 'notification_id' }})Marcar Múltiples Como Leídas
Section titled “Marcar Múltiples Como Leídas”Marcar múltiples notificaciones como leídas mediante un array de IDs.
- URL:
/api/v1/notifications/mark-as-read - Método:
POST - Autenticación Requerida: Sí
Cuerpo de Solicitud
Section titled “Cuerpo de Solicitud”{ "notificationIds": ["id_1", "id_2"]}Respuesta
Section titled “Respuesta”{ "success": true, "updated": 2, "message": "2 notificaciones marcadas como leídas"}Ejemplo de Cliente Hono
Section titled “Ejemplo de Cliente Hono”import { hcWithType } from '@vitality-gym/api/client'
const client = hcWithType('http://localhost:3000')
const res = await client.api.v1.notifications['mark-as-read'].$post({ json: { notificationIds: ['id_1', 'id_2'] }})Marcar Todas Como Leídas
Section titled “Marcar Todas Como Leídas”Marcar todas las notificaciones del usuario como leídas.
- URL:
/api/v1/notifications/mark-all-as-read - Método:
POST - Autenticación Requerida: Sí
Descripción Interna
Section titled “Descripción Interna”Este endpoint marca todas las notificaciones como leídas:
-
Actualiza en batch todas las notificaciones donde:
- userProfileId coincide
- readAt es null
-
Establece:
- status: READ
- readAt: Fecha actual
-
Retorna conteo de actualizadas
Respuesta
Section titled “Respuesta”{ "data": { "updated": 5, "message": "5 notificaciones marcadas como leídas" }}Crear Suscripción Push
Section titled “Crear Suscripción Push”Registrar una suscripción push.
- URL:
/api/v1/notifications/subscriptions - Método:
POST - Autenticación Requerida: Sí
Descripción Interna
Section titled “Descripción Interna”Este endpoint registra una suscripción push:
- Verifica si existe suscripción con mismo endpoint
- Si existe: Actualiza p256dh, auth, userAgent, deviceName y reactiva
- Si no existe: Crea nueva suscripción
Campos de Suscripción
Section titled “Campos de Suscripción”endpoint: URL del servicio pushp256dh: Clave pública del clienteauth: Secreto de autenticaciónuserAgent: Identificador del navegadordeviceName: Nombre del dispositivo (opcional)
Cuerpo de Solicitud
Section titled “Cuerpo de Solicitud”{ "endpoint": "https://fcm.googleapis.com/...", "keys": { "p256dh": "...", "auth": "..." }}Ejemplo de Cliente Hono
Section titled “Ejemplo de Cliente Hono”import { hcWithType } from '@vitality-gym/api/client'
const client = hcWithType('http://localhost:3000')
const res = await client.api.v1.notifications.subscriptions.$post({ json: { endpoint: 'https://...', keys: { p256dh: '...', auth: '...' } }})Actualizar Suscripción Push
Section titled “Actualizar Suscripción Push”Actualizar datos de una suscripción.
- URL:
/api/v1/notifications/subscriptions/:subscriptionId - Método:
PATCH - Autenticación Requerida: Sí
Cuerpo de Solicitud (Parcial)
Section titled “Cuerpo de Solicitud (Parcial)”{ "deviceName": "My iPhone", "isActive": false}Respuesta
Section titled “Respuesta”{ "success": true, "message": "Suscripción actualizada correctamente"}Ejemplo de Cliente Hono
Section titled “Ejemplo de Cliente Hono”import { hcWithType } from '@vitality-gym/api/client'
const client = hcWithType('http://localhost:3000')
const res = await client.api.v1.notifications.subscriptions[':subscriptionId'].$patch({ param: { subscriptionId: 'sub_id' }, json: { deviceName: 'My iPhone', isActive: false }})Eliminar Suscripción Push
Section titled “Eliminar Suscripción Push”Eliminar una suscripción push por ID.
- URL:
/api/v1/notifications/subscriptions/:subscriptionId - Método:
DELETE - Autenticación Requerida: Sí
Descripción Interna
Section titled “Descripción Interna”Este endpoint elimina una suscripción push validando primero que el usuario sea el dueño.
Eliminar Suscripción por Endpoint
Section titled “Eliminar Suscripción por Endpoint”Eliminar una suscripción dado el endpoint.
- URL:
/api/v1/notifications/subscriptions/unsubscribe - Método:
POST - Autenticación Requerida: Sí
Cuerpo de Solicitud
Section titled “Cuerpo de Solicitud”{ "endpoint": "https://fcm.googleapis.com/..."}Respuesta
Section titled “Respuesta”{ "success": true, "message": "Suscripción eliminada correctamente"}Ejemplo de Cliente Hono
Section titled “Ejemplo de Cliente Hono”import { hcWithType } from '@vitality-gym/api/client'
const client = hcWithType('http://localhost:3000')
const res = await client.api.v1.notifications.subscriptions.unsubscribe.$post({ json: { endpoint: 'https://fcm.googleapis.com/...' }})Crear Notificación (Admin)
Section titled “Crear Notificación (Admin)”Crear y enviar una notificación.
- URL:
/api/v1/notifications - Método:
POST - Autenticación Requerida: Sí (Admin)
Descripción Interna
Section titled “Descripción Interna”Este endpoint crea y envía una notificación:
-
Crea la notificación en la base de datos con:
- Todos los campos proporcionados
- status: SENT (o PENDING si programada)
- sentAt: Ahora (o null si programada)
-
Si no está programada, envía inmediatamente:
- Obtiene suscripciones push activas del usuario
- Construye payload con título, body, icon, etc.
- Envía a todos los dispositivos
- Actualiza status a DELIVERED si exitoso
-
Manejo de errores push:
- Si error 410 (Gone): Desactiva la suscripción
Cuerpo de Solicitud
Section titled “Cuerpo de Solicitud”{ "userProfileId": "user_id", "type": "CUSTOM", "title": "New Announcement", "body": "Check out our new classes!", "icon": "🔔", "priority": "HIGH", "data": { "url": "/classes" }}Difundir Notificación (Admin)
Section titled “Difundir Notificación (Admin)”Enviar notificación a múltiples usuarios.
- URL:
/api/v1/notifications/broadcast - Método:
POST - Autenticación Requerida: Sí (Admin)
Descripción Interna
Section titled “Descripción Interna”Este endpoint envía notificaciones masivas:
-
Obtiene usuarios objetivo según filtros:
targetRoles: Filtrar por roles específicostargetUserIds: Lista específica de usuarios
-
Valida que haya usuarios para enviar
-
Crea notificación para cada usuario encontrado
-
Retorna conteo de enviadas
Cuerpo de Solicitud
Section titled “Cuerpo de Solicitud”{ "targetRoles": ["MEMBER"], "type": "ANNOUNCEMENT", "title": "Gym Update", "body": "New equipment available!"}Obtener Plantillas de Notificación (Admin)
Section titled “Obtener Plantillas de Notificación (Admin)”Obtener todas las plantillas de notificación.
- URL:
/api/v1/notifications/templates - Método:
GET - Autenticación Requerida: Sí (Admin)
Descripción Interna
Section titled “Descripción Interna”Este endpoint obtiene plantillas de notificación:
-
Filtros disponibles:
type: Tipo de plantillaisActive: Solo plantillas activas
-
Ordenamiento por sortBy/sortOrder
-
Paginación estándar
Plantillas
Section titled “Plantillas”Las plantillas permiten definir notificaciones reutilizables con variables como {{userName}}, {{className}}, etc.
Enviar Desde Plantilla (Admin)
Section titled “Enviar Desde Plantilla (Admin)”Enviar notificación usando una plantilla.
- URL:
/api/v1/notifications/from-template - Método:
POST - Autenticación Requerida: Sí (Admin)
Descripción Interna
Section titled “Descripción Interna”Este endpoint envía notificaciones desde plantilla:
- Obtiene plantilla por tipo
- Verifica que esté activa
- Reemplaza variables en título y body:
- Busca
{{variable}}y reemplaza con valores proporcionados
- Busca
- Crea notificaciones para cada userProfileId
- Configura expiración según TTL de plantilla
Cuerpo de Solicitud
Section titled “Cuerpo de Solicitud”{ "type": "RESERVATION_REMINDER", "userProfileIds": ["user_1", "user_2"], "variables": { "className": "Yoga", "date": "2023-10-27" }}Obtener Todas las Notificaciones (Admin)
Section titled “Obtener Todas las Notificaciones (Admin)”- URL:
/api/v1/notifications/admin/all - Método:
GET - Autenticación Requerida: Sí (Admin/Staff)
Obtener Avisos Agrupados (Admin)
Section titled “Obtener Avisos Agrupados (Admin)”- URL:
/api/v1/notifications/admin/announcements - Método:
GET - Autenticación Requerida: Sí (Admin/Staff)
Procesar Notificaciones Programadas (Admin)
Section titled “Procesar Notificaciones Programadas (Admin)”- URL:
/api/v1/notifications/admin/process-scheduled - Método:
POST - Autenticación Requerida: Sí (Admin)
Respuesta
Section titled “Respuesta”{ "success": true, "processed": 5, "message": "5 notificaciones procesadas"}Limpiar Notificaciones Expiradas (Admin)
Section titled “Limpiar Notificaciones Expiradas (Admin)”- URL:
/api/v1/notifications/admin/cleanup-expired - Método:
POST - Autenticación Requerida: Sí (Admin)
Respuesta
Section titled “Respuesta”{ "success": true, "expired": 10, "message": "10 notificaciones expiradas han sido eliminadas/ocultas."}Crear Plantilla de Notificación (Admin)
Section titled “Crear Plantilla de Notificación (Admin)”- URL:
/api/v1/notifications/templates - Método:
POST - Autenticación Requerida: Sí (Admin)
Cuerpo de Solicitud
Section titled “Cuerpo de Solicitud”{ "type": "CUSTOM", "title": "Aviso: {{title}}", "body": "Hola, esto es un mensaje: {{message}}", "variables": ["title", "message"], "priority": "HIGH"}Actualizar Plantilla de Notificación (Admin)
Section titled “Actualizar Plantilla de Notificación (Admin)”- URL:
/api/v1/notifications/templates/:templateId - Método:
PATCH - Autenticación Requerida: Sí (Admin)
Cuerpo de Solicitud (Parcial)
Section titled “Cuerpo de Solicitud (Parcial)”{ "isActive": false}Eliminar Plantilla de Notificación (Admin)
Section titled “Eliminar Plantilla de Notificación (Admin)”- URL:
/api/v1/notifications/templates/:templateId - Método:
DELETE - Autenticación Requerida: Sí (Admin)
Enviar desde Plantilla (Admin/Staff)
Section titled “Enviar desde Plantilla (Admin/Staff)”- URL:
/api/v1/notifications/templates/send - Método:
POST - Autenticación Requerida: Sí (Admin/Staff)
Cuerpo de Solicitud
Section titled “Cuerpo de Solicitud”{ "type": "CUSTOM", "userProfileIds": ["user_1"], "variables": { "title": "Cierre Mañana", "message": "Mañana cerramos a las 5PM" }}Obtener Estadísticas de Notificaciones (Admin)
Section titled “Obtener Estadísticas de Notificaciones (Admin)”Obtener estadísticas de notificaciones.
- URL:
/api/v1/notifications/stats - Método:
GET - Autenticación Requerida: Sí (Admin)
Descripción Interna
Section titled “Descripción Interna”Este endpoint calcula estadísticas de notificaciones:
-
Conteos:
- Total de notificaciones
- No leídas
- Leídas
-
Tasa de lectura: (leídas / total) × 100
-
Agrupaciones:
- Por status
- Por tipo
- Por prioridad
Respuesta
Section titled “Respuesta”{ "data": { "total": 1000, "unread": 150, "read": 850, "readRate": 85.0, "byStatus": [ { "status": "READ", "count": 850 }, { "status": "DELIVERED", "count": 100 } ], "byType": [...], "byPriority": [...] }}