extraer-patron-como-skill

CULTIVA IA · Productividad · Automatización de conocimiento

✅ Extracción completa
🔄Pipeline de extracción ejecutado
Paso 1
Identificar patrón
Webhook LS · n8n · fallo silencioso
Paso 2
Determinar alcance
3 proyectos afectados · 2 h debugging
Paso 3
Generar nombre
ls-webhook-custom-data
Paso 4
Crear archivos
SKILL.md · README.md · examples.md
Paso 5
Quality gates
7/7 checks ✅
📥Input analizado
Patrón detectado
Lemon Squeezy webhook + n8n onboarding falla silenciosamente
n8n Lemon Squeezy 3 proyectos silent fail custom_data JSON.parse()
Tiempo de debugging invertido
~2 horas
× 3 proyectos = 6 h recuperables
📊Criterios de extracción
Criterio Estado
Recurrente (2+ proyectos) ✓ 3 proyectos
No obvio (requirió debugging) ✓ 2 h debug
Ampliamente aplicable ✓ Stack genérico
Solución multi-paso ✓ 4 pasos
Flaggeado por usuario ✓ Explicit

Skill extraída: ls-webhook-custom-data

Skill portable generada en ./ls-webhook-custom-data/ — lista para instalar en cualquier proyecto con /plugin install o copiar a tu directorio de skills.

📄SKILL.md generado — vista previa
ls-webhook-custom-data/SKILL.md
---
name: "ls-webhook-custom-data"
description: "Fix para Lemon Squeezy webhook que envía custom_data como string JSON-encoded
  y falla silenciosamente en n8n si falta client_id. Use when: integrando checkout LS
  con n8n y el flujo de onboarding no dispara sin errores visibles."
---

# ls-webhook-custom-data

## Quick Reference

| Problema | Solución |
|----------|----------|
| custom_data llega como string, no objeto | Nodo Set: JSON.parse({{ $json.custom_data }}) |
| Flujo no dispara, sin error en logs n8n | Validar client_id en primer nodo con throw explícito |
| Error solo visible en callback LS | Habilitar webhook debug log en LS settings |
| Silent no-op en nodo If downstream | Añadir nodo Error Trigger como fallback |

## The Problem

Lemon Squeezy serializa el campo custom_data como string JSON-encoded antes de enviarlo
al webhook — no como objeto nativo. n8n recibe este campo como texto plano y no lo parsea
automáticamente, por lo que cualquier acceso a $json.custom_data.client_id devuelve
undefined sin lanzar ningún error. El nodo If downstream lo interpreta como condición
false y el flujo se detiene silenciosamente.

## Solutions

### Option 1: Nodo Set + JSON.parse (Recomendado)

Añadir un nodo Set inmediatamente después del webhook trigger:

```javascript
// Expresión n8n en el nodo Set → campo "parsedData"
{{ JSON.parse($json.custom_data) }}
```

Luego validar en un nodo Function:

```javascript
const data = $input.first().json.parsedData;
if (!data?.client_id) {
  throw new Error('[ls-webhook] client_id ausente en custom_data');
}
return [{ json: { ...data } }];
```

### Option 2: Code Node con try/catch

Para entornos donde no se puede añadir nodos intermedios:

```javascript
let customData;
try {
  customData = JSON.parse($json.custom_data ?? '{}');
} catch (e) {
  throw new Error(`[ls-webhook] custom_data no es JSON válido: ${e.message}`);
}
if (!customData.client_id) throw new Error('client_id requerido');
return [{ json: customData }];
```

## Trade-offs

| Enfoque | Pros | Contras |
|---------|------|---------|
| Nodo Set + Function | Visual, editable sin código | +2 nodos en el flujo |
| Code Node único | Compacto, portable | Menos visible para no-devs |
| Error Trigger fallback | Captura todos los silent fails | Requiere canal de alertas |

## Edge Cases

- custom_data puede ser null: usar $json.custom_data ?? '{}' antes de parsear
- Webhooks de test LS: omiten custom_data — añadir guard if ($json.meta?.test_mode)
- Reintentos automáticos LS: el webhook reintenta 3× — el throw explícito evita duplicados
📁Archivos creados
📄 SKILL.md 89 líneas
📖 README.md 42 líneas
🗂️ reference/examples.md 67 líneas
Estructura de la skill
ls-webhook-custom-data/
├── SKILL.md
├── README.md
└── reference/
    └── examples.md
Comandos de instalación
# Instalar en proyecto actual
/plugin install ls-webhook-custom-data

# Publicar al hub
clawhub publish ./ls-webhook-custom-data
Quality gates — 7/7 pasados
SKILL.md con frontmatter YAML válido (name + description)
Nombre coincide con carpeta (lowercase, hyphens)
No contiene fragmentos reservados (claude/anthropic)
Description incluye condiciones "Use when:"
Soluciones autocontenidas, sin contexto externo
Ejemplos de código completos y copy-pasteables
Sin valores hardcoded (paths, URLs, credentials)
📈Impacto estimado de la skill
6h
Tiempo recuperado (3 proyectos × 2h)
3
Proyectos ya afectados
~15min
Tiempo de extracción total
Proyectos futuros protegidos
7/7
Quality gates superados
CULTIVA IA · Skill: extraer-patron-como-skill · Ejecutado 2026-06-12 · ID 2f90f135