WebChatV2/docs/N8N_CONTRACT.md

115 lines
4.4 KiB
Markdown
Raw Permalink Normal View History

# Contrato de integración con n8n — WebChatV2
El frontend hace un `POST` al **webhook de n8n** con el mensaje del usuario y el historial,
y espera una respuesta JSON con el texto del asistente y, opcionalmente, KeyNotes
(resumen / To-Do) que se insertan automáticamente en el panel derecho y que el usuario
puede editar después.
## 1. Configuración de la URL
La URL del webhook se resuelve en **tiempo de ejecución** (no se "hornea" al compilar),
para que puedas cambiarla sin reconstruir la imagen Docker:
1. `public/config.js` → define `window.APP_CONFIG.N8N_WEBHOOK_URL` (prioridad alta).
2. Si no existe, se usa la variable de entorno `VITE_N8N_WEBHOOK_URL` (definida al compilar).
En Docker, edita el archivo `config.js` servido por nginx (o monta un volumen sobre
`/usr/share/nginx/html/config.js`) y recarga la página.
## 2. Request — `POST {N8N_WEBHOOK_URL}`
`Content-Type: application/json`
```json
{
"themeId": "theme_abc123",
"subThemeId": "sub_def456",
"themeTitle": "Tema Principal",
"subThemeTitle": "Subtema 1",
"history": [
{ "role": "user", "content": "Hola" },
{ "role": "assistant", "content": "¿En qué puedo ayudarte?" }
],
"message": "Explícame cómo funciona esto"
}
```
| Campo | Tipo | Descripción |
| --------------- | -------- | ------------------------------------------------------------------ |
| `themeId` | string | ID del MainTheme activo. Útil para guardar contexto en n8n/DB. |
| `subThemeId` | string | ID del SubTheme activo (la conversación actual). |
| `themeTitle` | string | Título del tema (legible). |
| `subThemeTitle` | string | Título del subtema (legible). |
| `history` | array | Mensajes previos `{role, content}` (orden cronológico). |
| `message` | string | Texto que el usuario acaba de escribir (NO está incluido en history).|
`role` es `"user"` | `"assistant"`.
## 3. Response — `200 OK` (JSON)
```json
{
"reply": "Respuesta en **Markdown** del asistente…",
"keyNotes": [
{
"type": "summary",
"title": "Resumen de la conversación",
"content": "Puntos clave tratados…"
},
{
"type": "todo",
"title": "Tareas pendientes",
"items": [
{ "text": "Revisar la documentación", "done": false },
{ "text": "Configurar el webhook", "done": true }
]
}
]
}
```
### Reglas
- `reply` (**obligatorio**, `string`): texto de respuesta. Se renderiza como **Markdown**
(soporta GFM: listas, tablas, bloques de código, etc.).
- `keyNotes` (**opcional**, `array`): notas que se añaden al SubTheme activo con
`source: "n8n"`. El usuario puede editarlas/eliminarlas libremente.
### Tipos de KeyNote
| `type` | Requiere |
| --------- | -------------------------------------------------------- |
| `summary` | `title` + `content` (string, Markdown plano) |
| `todo` | `title` + `items[]` con `{ text: string, done?: boolean }` |
| `free` | `title` + `content` |
`done` es opcional y por defecto `false`.
## 4. Errores y timeouts
- Cualquier status HTTP fuera del rango 2xx se trata como error y se marca el mensaje
como `status: "error"`. El usuario puede pulsar **Reintentar**.
- Timeout por defecto: **120 s**. La solicitud puede cancelarse con el botón **Detener**
(usa `AbortController`), lo que aborta el fetch hacia n8n.
## 5. Ejemplo de workflow n8n (orientativo)
```
Webhook (POST /webhook/chat)
→ Set (extraer body.message, body.history, body.themeTitle…)
→ [tu LLM / lógica]
→ Set (construir JSON { reply, keyNotes })
→ Respond to Webhook (JSON, 200)
```
> En n8n usa el nodo **Respond to Webhook** con `Respond With: JSON` y en `Response Body`
> pega el objeto `{ "reply": ..., "keyNotes": [...] }`.
## 6. Evolución futura (streaming / persistencia en DB)
- **Streaming:** el contrato queda preparado para añadir SSE (`text/event-stream`)
más adelante sin romper la UI (el indicador "escribiendo…" ya existe).
- **Persistencia:** el estado vive hoy en `localStorage`. Para sincronizar con una DB
vía n8n, añade endpoints `GET/POST /webhook/state` y reemplaza el adapter en
`src/store/persistence.ts` (punto único de intercambio).