template-saas/docs/01-modulos/SAAS-010-webhooks.md
rckrdmrd 50a821a415
Some checks failed
CI / Backend CI (push) Has been cancelled
CI / Frontend CI (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / CI Summary (push) Has been cancelled
[SIMCO-V38] feat: Actualizar a SIMCO v3.8.0
- HERENCIA-SIMCO.md actualizado con directivas v3.7 y v3.8
- Actualizaciones de configuracion

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 08:53:08 -06:00

6.8 KiB

id title type status priority module version created_date updated_date
SAAS-010 Webhooks Module Published P2 webhooks 1.0.0 2026-01-07 2026-01-10

SAAS-010: Webhooks

Metadata

  • Codigo: SAAS-010
  • Modulo: Webhooks
  • Prioridad: P2
  • Estado: Implementado
  • Fase: 5 - Integraciones

Descripcion

Sistema de webhooks outbound: configuracion de endpoints por tenant, eventos suscribibles, firma de payloads, reintentos automaticos, y logs de entregas.

Objetivos

  1. Configuracion de webhooks por tenant
  2. Eventos suscribibles
  3. Firma HMAC de payloads
  4. Reintentos con backoff
  5. Dashboard de entregas

Implementacion

Estado de Entregables

Entregable Estado Archivo
webhooks.module.ts Implementado apps/backend/src/modules/webhooks/webhooks.module.ts
webhooks.controller.ts Implementado apps/backend/src/modules/webhooks/webhooks.controller.ts
webhook.service.ts Implementado apps/backend/src/modules/webhooks/services/webhook.service.ts
webhook.processor.ts Implementado apps/backend/src/modules/webhooks/processors/webhook.processor.ts
DDL webhooks schema Implementado apps/database/ddl/schemas/webhooks/

Archivos Creados

Backend:

apps/backend/src/modules/webhooks/
├── webhooks.module.ts          # NestJS module with BullMQ
├── webhooks.controller.ts      # REST endpoints (10 endpoints)
├── index.ts                    # Module barrel export
├── entities/
│   ├── webhook.entity.ts       # WebhookEntity, WebhookDeliveryEntity
│   └── index.ts
├── dto/
│   ├── webhook.dto.ts          # Request/Response DTOs
│   └── index.ts
├── processors/
│   ├── webhook.processor.ts    # BullMQ worker for deliveries
│   └── index.ts
└── services/
    ├── webhook.service.ts      # Business logic
    └── index.ts

Database:

apps/database/ddl/schemas/webhooks/tables/
├── 01-webhooks.sql             # Main webhooks table
└── 02-deliveries.sql           # Delivery logs, retry functions

Tablas de Base de Datos

Tabla Descripcion
webhooks.webhooks Configuracion de webhooks por tenant
webhooks.deliveries Historial de entregas y reintentos

Funciones de Base de Datos

Funcion Descripcion
webhooks.calculate_next_retry() Calcula tiempo de siguiente reintento
webhooks.get_pending_retries() Obtiene entregas pendientes de retry
webhooks.get_webhook_stats() Estadisticas de un webhook

Eventos Disponibles

Evento Descripcion Payload
user.created Usuario creado User object
user.updated Usuario actualizado User + changes
user.deleted Usuario eliminado { userId }
subscription.created Nueva suscripcion Subscription
subscription.updated Suscripcion cambiada Subscription
subscription.cancelled Suscripcion cancelada Subscription
invoice.paid Factura pagada Invoice
invoice.failed Pago fallido Invoice
file.uploaded Archivo subido File object
file.deleted Archivo eliminado { fileId }
tenant.updated Tenant actualizado Tenant object

Endpoints API

Metodo Endpoint Descripcion Implementado
GET /webhooks/events Listar eventos disponibles
GET /webhooks Listar webhooks
GET /webhooks/:id Obtener webhook
POST /webhooks Crear webhook
PUT /webhooks/:id Actualizar webhook
DELETE /webhooks/:id Eliminar webhook
POST /webhooks/:id/regenerate-secret Regenerar secret
POST /webhooks/:id/test Enviar test
GET /webhooks/:id/deliveries Historial entregas
POST /webhooks/:id/deliveries/:did/retry Reintentar

Firma de Payloads

Generacion

function signPayload(payload: object, secret: string): string {
  const timestamp = Date.now();
  const body = JSON.stringify(payload);
  const signature = crypto
    .createHmac('sha256', secret)
    .update(`${timestamp}.${body}`)
    .digest('hex');

  return `t=${timestamp},v1=${signature}`;
}

Headers Enviados

X-Webhook-Signature: t=1704067200000,v1=abc123...
X-Webhook-Id: <webhook-uuid>
X-Webhook-Event: user.created
X-Webhook-Timestamp: 1704067200000
X-Webhook-Delivery: <delivery-uuid>

Verificacion (lado receptor)

function verifySignature(payload: string, signature: string, secret: string): boolean {
  const [timestamp, hash] = parseSignature(signature);

  // Verificar timestamp (5 min tolerance)
  if (Date.now() - timestamp > 300000) return false;

  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${timestamp}.${payload}`)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(hash),
    Buffer.from(expected)
  );
}

Logica de Reintentos

Intento 1: Inmediato
Intento 2: +1 minuto
Intento 3: +5 minutos
Intento 4: +30 minutos
Intento 5: +2 horas
Intento 6: +6 horas
Despues: Marcar como fallido

Status de Entrega

Status Descripcion
pending En cola
delivered Entregado (2xx)
failed Fallo permanente
retrying En reintento

Limites por Plan

Plan Webhooks Eventos/mes
Free 0 0
Starter 0 0
Pro 5 10,000
Enterprise 20 100,000

Dependencias

Tecnologicas

  • BullMQ para queue (Redis)
  • NestJS @nestjs/bullmq
  • ioredis

Depende de

  • SAAS-002 (Tenants)
  • SAAS-005 (Plans - feature flag)

Bloquea a

  • Integraciones de terceros
  • Automatizaciones externas

Criterios de Aceptacion

  • CRUD webhooks funciona
  • Eventos se disparan
  • Firma es correcta
  • Reintentos funcionan
  • Test endpoint funciona
  • Logs se registran

Configuracion

Variables de Entorno

# Redis for BullMQ
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=  # Optional

Seguridad

  • Secrets generados aleatoriamente (whsec_...)
  • HTTPS requerido para URLs
  • Timeout de 30 segundos
  • Rate limit por tenant
  • No seguir redirects

Uso

Crear Webhook

POST /webhooks
{
  "name": "My Webhook",
  "url": "https://example.com/webhook",
  "events": ["user.created", "subscription.created"],
  "headers": {
    "X-Custom-Header": "value"
  }
}

Dispatch Event (desde otros servicios)

// Inyectar WebhookService
constructor(private webhookService: WebhookService) {}

// Disparar evento
await this.webhookService.dispatch(
  tenantId,
  'user.created',
  { id: user.id, email: user.email }
);

Ultima actualizacion: 2026-01-10