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

269 lines
6.8 KiB
Markdown

---
id: "SAAS-010"
title: "Webhooks"
type: "Module"
status: "Published"
priority: "P2"
module: "webhooks"
version: "1.0.0"
created_date: "2026-01-07"
updated_date: "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
```typescript
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)
```typescript
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
- [x] CRUD webhooks funciona
- [x] Eventos se disparan
- [x] Firma es correcta
- [x] Reintentos funcionan
- [x] Test endpoint funciona
- [x] Logs se registran
## Configuracion
### Variables de Entorno
```bash
# 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
```typescript
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)
```typescript
// 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