@qubiit/lmagent 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/.editorconfig +18 -0
  2. package/AGENTS.md +169 -0
  3. package/CLAUDE.md +122 -0
  4. package/CONTRIBUTING.md +90 -0
  5. package/LICENSE +21 -0
  6. package/README.md +195 -0
  7. package/config/commands.yaml +194 -0
  8. package/config/levels.yaml +135 -0
  9. package/config/models.yaml +192 -0
  10. package/config/settings.yaml +405 -0
  11. package/config/tools-extended.yaml +534 -0
  12. package/config/tools.yaml +437 -0
  13. package/docs/assets/logo.png +0 -0
  14. package/docs/commands.md +132 -0
  15. package/docs/customization-guide.md +445 -0
  16. package/docs/getting-started.md +154 -0
  17. package/docs/how-to-start.md +242 -0
  18. package/docs/navigation-index.md +227 -0
  19. package/docs/usage-guide.md +113 -0
  20. package/install.js +1044 -0
  21. package/package.json +35 -0
  22. package/pyproject.toml +182 -0
  23. package/rules/_bootstrap.md +138 -0
  24. package/rules/agents-ia.md +607 -0
  25. package/rules/api-design.md +337 -0
  26. package/rules/automations-n8n.md +646 -0
  27. package/rules/code-style.md +570 -0
  28. package/rules/documentation.md +98 -0
  29. package/rules/security.md +316 -0
  30. package/rules/stack.md +395 -0
  31. package/rules/testing.md +326 -0
  32. package/rules/workflow.md +353 -0
  33. package/scripts/create_skill.js +300 -0
  34. package/scripts/validate_skills.js +283 -0
  35. package/skills/ai-agent-engineer/SKILL.md +394 -0
  36. package/skills/ai-agent-engineer/references/agent-patterns.md +149 -0
  37. package/skills/api-designer/SKILL.md +429 -0
  38. package/skills/api-designer/references/api-standards.md +13 -0
  39. package/skills/architect/SKILL.md +285 -0
  40. package/skills/architect/references/c4-model.md +133 -0
  41. package/skills/automation-engineer/SKILL.md +352 -0
  42. package/skills/automation-engineer/references/n8n-patterns.md +127 -0
  43. package/skills/backend-engineer/SKILL.md +261 -0
  44. package/skills/backend-engineer/assets/fastapi-project-structure.yaml +74 -0
  45. package/skills/backend-engineer/references/debugging-guide.md +174 -0
  46. package/skills/backend-engineer/references/design-patterns.md +208 -0
  47. package/skills/backend-engineer/scripts/scaffold_backend.py +313 -0
  48. package/skills/bmad-methodology/SKILL.md +202 -0
  49. package/skills/bmad-methodology/references/scale-adaptive-levels.md +141 -0
  50. package/skills/browser-agent/SKILL.md +502 -0
  51. package/skills/browser-agent/scripts/playwright_setup.ts +16 -0
  52. package/skills/code-reviewer/SKILL.md +306 -0
  53. package/skills/code-reviewer/references/code-review-checklist.md +16 -0
  54. package/skills/data-engineer/SKILL.md +474 -0
  55. package/skills/data-engineer/assets/pg-monitoring-queries.sql +154 -0
  56. package/skills/data-engineer/references/index-strategy.md +128 -0
  57. package/skills/data-engineer/scripts/backup_postgres.py +221 -0
  58. package/skills/devops-engineer/SKILL.md +547 -0
  59. package/skills/devops-engineer/references/ci-cd-patterns.md +265 -0
  60. package/skills/devops-engineer/scripts/docker_healthcheck.py +125 -0
  61. package/skills/document-generator/SKILL.md +746 -0
  62. package/skills/document-generator/references/pdf-generation.md +22 -0
  63. package/skills/frontend-engineer/SKILL.md +532 -0
  64. package/skills/frontend-engineer/references/accessibility-guide.md +146 -0
  65. package/skills/frontend-engineer/scripts/audit_bundle.py +144 -0
  66. package/skills/git-workflow/SKILL.md +374 -0
  67. package/skills/git-workflow/references/git-flow.md +25 -0
  68. package/skills/mcp-builder/SKILL.md +471 -0
  69. package/skills/mcp-builder/references/mcp-server-guide.md +23 -0
  70. package/skills/mobile-engineer/SKILL.md +502 -0
  71. package/skills/mobile-engineer/references/platform-guidelines.md +160 -0
  72. package/skills/orchestrator/SKILL.md +246 -0
  73. package/skills/orchestrator/references/methodology-routing.md +117 -0
  74. package/skills/orchestrator/references/persona-mapping.md +85 -0
  75. package/skills/orchestrator/references/routing-logic.md +110 -0
  76. package/skills/performance-engineer/SKILL.md +549 -0
  77. package/skills/performance-engineer/references/caching-patterns.md +181 -0
  78. package/skills/performance-engineer/scripts/profile_endpoint.py +170 -0
  79. package/skills/product-manager/SKILL.md +488 -0
  80. package/skills/product-manager/references/prioritization-frameworks.md +126 -0
  81. package/skills/prompt-engineer/SKILL.md +433 -0
  82. package/skills/prompt-engineer/references/prompt-patterns.md +158 -0
  83. package/skills/qa-engineer/SKILL.md +441 -0
  84. package/skills/qa-engineer/references/testing-strategy.md +166 -0
  85. package/skills/qa-engineer/scripts/run_coverage.py +147 -0
  86. package/skills/scrum-master/SKILL.md +225 -0
  87. package/skills/scrum-master/references/sprint-ceremonies.md +159 -0
  88. package/skills/security-analyst/SKILL.md +390 -0
  89. package/skills/security-analyst/references/owasp-top10.md +188 -0
  90. package/skills/security-analyst/scripts/audit_security.py +242 -0
  91. package/skills/seo-auditor/SKILL.md +523 -0
  92. package/skills/seo-auditor/references/seo-checklist.md +17 -0
  93. package/skills/spec-driven-dev/SKILL.md +342 -0
  94. package/skills/spec-driven-dev/references/phase-gates.md +107 -0
  95. package/skills/supabase-expert/SKILL.md +602 -0
  96. package/skills/supabase-expert/references/supabase-patterns.md +19 -0
  97. package/skills/swe-agent/SKILL.md +311 -0
  98. package/skills/swe-agent/references/trajectory-format.md +134 -0
  99. package/skills/systematic-debugger/SKILL.md +512 -0
  100. package/skills/systematic-debugger/references/debugging-guide.md +12 -0
  101. package/skills/tech-lead/SKILL.md +409 -0
  102. package/skills/tech-lead/references/code-review-checklist.md +111 -0
  103. package/skills/technical-writer/SKILL.md +631 -0
  104. package/skills/technical-writer/references/doc-templates.md +218 -0
  105. package/skills/testing-strategist/SKILL.md +476 -0
  106. package/skills/testing-strategist/references/testing-pyramid.md +16 -0
  107. package/skills/ux-ui-designer/SKILL.md +419 -0
  108. package/skills/ux-ui-designer/references/design-system-foundation.md +168 -0
  109. package/skills_overview.txt +94 -0
  110. package/templates/PROJECT_KICKOFF.md +284 -0
  111. package/templates/SKILL_TEMPLATE.md +131 -0
  112. package/templates/USAGE.md +95 -0
  113. package/templates/agent-python/README.md +71 -0
  114. package/templates/agent-python/agent.py +272 -0
  115. package/templates/agent-python/config.yaml +76 -0
  116. package/templates/agent-python/prompts/system.md +109 -0
  117. package/templates/agent-python/requirements.txt +7 -0
  118. package/templates/automation-n8n/README.md +14 -0
  119. package/templates/automation-n8n/webhook-handler.json +57 -0
  120. package/templates/backend-node/Dockerfile +12 -0
  121. package/templates/backend-node/README.md +15 -0
  122. package/templates/backend-node/package.json +30 -0
  123. package/templates/backend-node/src/index.ts +19 -0
  124. package/templates/backend-node/src/routes.ts +7 -0
  125. package/templates/backend-node/tsconfig.json +22 -0
  126. package/templates/backend-python/Dockerfile +11 -0
  127. package/templates/backend-python/README.md +78 -0
  128. package/templates/backend-python/app/core/config.py +12 -0
  129. package/templates/backend-python/app/core/database.py +12 -0
  130. package/templates/backend-python/app/main.py +17 -0
  131. package/templates/backend-python/app/routers/__init__.py +1 -0
  132. package/templates/backend-python/app/routers/health.py +7 -0
  133. package/templates/backend-python/requirements-dev.txt +6 -0
  134. package/templates/backend-python/requirements.txt +4 -0
  135. package/templates/backend-python/tests/test_health.py +9 -0
  136. package/templates/checkpoint.yaml +117 -0
  137. package/templates/database/README.md +474 -0
  138. package/templates/frontend-react/README.md +446 -0
  139. package/templates/plan.yaml +320 -0
  140. package/templates/session.yaml +125 -0
  141. package/templates/spec.yaml +229 -0
  142. package/templates/tasks.yaml +330 -0
  143. package/workflows/bugfix-backend.md +380 -0
  144. package/workflows/documentation.md +232 -0
  145. package/workflows/generate-prd.md +320 -0
  146. package/workflows/ideation.md +396 -0
  147. package/workflows/new-agent-ia.md +497 -0
  148. package/workflows/new-automation.md +374 -0
  149. package/workflows/new-feature.md +290 -0
  150. package/workflows/optimize-performance.md +373 -0
  151. package/workflows/resolve-github-issue.md +524 -0
  152. package/workflows/security-review.md +291 -0
  153. package/workflows/spec-driven.md +476 -0
  154. package/workflows/testing-strategy.md +296 -0
  155. package/workflows/third-party-integration.md +277 -0
@@ -0,0 +1,646 @@
1
+ # Reglas para Integraciones con n8n - LMAgent
2
+
3
+ > **Tipo**: `rule` | **Versión**: 2.1 | **Actualización**: 2026-01
4
+
5
+ ## 📌 Quick Reference
6
+
7
+ | Principio | Regla |
8
+ |-----------|-------|
9
+ | **n8n-First** | Diseñar APIs pensando en cómo n8n las consumirá. |
10
+ | **Respuesta < 60s** | Procesos largos en background + polling o callback. |
11
+ | **Payloads Estables** | Nunca cambiar estructura sin versionar la API. |
12
+ | **Errores Útiles** | `{ success, error, error_code }` para que n8n procese. |
13
+ | **Idempotencia** | Re-ejecutar el mismo webhook debe dar el mismo resultado. |
14
+
15
+ ### 👥 Roles que usan esta regla
16
+ `automation-engineer`, `backend-engineer`, `architect`
17
+
18
+ ---
19
+
20
+ Este documento define las mejores prácticas para diseñar APIs y webhooks pensando en n8n.
21
+
22
+ ## Principios de Diseño
23
+
24
+ ### 1. n8n-First API Design
25
+ Cuando diseñes endpoints que serán consumidos por n8n:
26
+
27
+ - **Respuestas predecibles**: Siempre la misma estructura
28
+ - **Payloads estables**: No cambiar campos sin versionar
29
+ - **Documentación clara**: Ejemplos de JSON in/out
30
+ - **Errores útiles**: Mensajes que n8n pueda procesar
31
+
32
+ ### 2. Arquitectura de Integración
33
+ ```
34
+ ┌─────────────────────────────────────────────────────────────────┐
35
+ │ n8n Workflow │
36
+ └───────┬───────────────────────────────────────┬─────────────────┘
37
+ │ │
38
+ ▼ ▼
39
+ ┌───────────────┐ ┌───────────────┐
40
+ │ Webhook │ │ HTTP Request │
41
+ │ Trigger │ │ Node │
42
+ └───────┬───────┘ └───────┬───────┘
43
+ │ │
44
+ ▼ ▼
45
+ ┌─────────────────────────────────────────────────────────────────┐
46
+ │ Backend API (FastAPI/Express) │
47
+ │ │
48
+ │ POST /webhooks/event-name GET /api/v1/resource │
49
+ │ - Recibe eventos de n8n - Devuelve datos para n8n │
50
+ │ - Procesa en background - Paginación, filtros │
51
+ │ - Retorna confirmación - Formato consistente │
52
+ └─────────────────────────────────────────────────────────────────┘
53
+ ```
54
+
55
+ ---
56
+
57
+ ## Diseño de Webhooks
58
+
59
+ ### Estructura de Endpoint
60
+ ```python
61
+ from fastapi import APIRouter, BackgroundTasks, HTTPException
62
+ from pydantic import BaseModel, Field
63
+ from datetime import datetime
64
+ from uuid import uuid4
65
+
66
+ router = APIRouter(prefix="/webhooks", tags=["webhooks"])
67
+
68
+ # =====================================
69
+ # Schemas Estándar
70
+ # =====================================
71
+
72
+ class WebhookPayload(BaseModel):
73
+ """Payload estándar que n8n debe enviar."""
74
+ event_type: str = Field(..., description="Tipo de evento, ej: order.created")
75
+ timestamp: datetime = Field(default_factory=datetime.utcnow)
76
+ data: dict = Field(..., description="Datos del evento")
77
+ metadata: dict = Field(default_factory=dict, description="Metadatos opcionales")
78
+
79
+ model_config = {
80
+ "json_schema_extra": {
81
+ "example": {
82
+ "event_type": "order.created",
83
+ "timestamp": "2024-01-15T10:30:00Z",
84
+ "data": {
85
+ "order_id": "12345",
86
+ "customer_email": "customer@example.com",
87
+ "total": 99.99
88
+ },
89
+ "metadata": {
90
+ "source": "n8n",
91
+ "workflow_id": "abc123"
92
+ }
93
+ }
94
+ }
95
+ }
96
+
97
+ class WebhookResponse(BaseModel):
98
+ """Respuesta estándar para n8n."""
99
+ success: bool
100
+ message: str
101
+ request_id: str = Field(description="ID único para tracking")
102
+ processed_at: datetime
103
+
104
+ model_config = {
105
+ "json_schema_extra": {
106
+ "example": {
107
+ "success": True,
108
+ "message": "Event queued for processing",
109
+ "request_id": "550e8400-e29b-41d4-a716-446655440000",
110
+ "processed_at": "2024-01-15T10:30:01Z"
111
+ }
112
+ }
113
+ }
114
+
115
+ class WebhookError(BaseModel):
116
+ """Error estándar para n8n."""
117
+ success: bool = False
118
+ error: str
119
+ error_code: str
120
+ details: dict = {}
121
+ ```
122
+
123
+ ### Implementación de Webhook
124
+ ```python
125
+ @router.post(
126
+ "/order-created",
127
+ response_model=WebhookResponse,
128
+ responses={
129
+ 400: {"model": WebhookError, "description": "Invalid payload"},
130
+ 500: {"model": WebhookError, "description": "Processing error"}
131
+ }
132
+ )
133
+ async def handle_order_created(
134
+ payload: WebhookPayload,
135
+ background_tasks: BackgroundTasks
136
+ ) -> WebhookResponse:
137
+ """
138
+ Webhook para procesar órdenes creadas.
139
+
140
+ ## Uso en n8n
141
+
142
+ 1. Agregar nodo **HTTP Request**
143
+ 2. **Method**: POST
144
+ 3. **URL**: `{{$env.BACKEND_URL}}/webhooks/order-created`
145
+ 4. **Headers**:
146
+ - Content-Type: application/json
147
+ - X-API-Key: {{$env.API_KEY}} (si se requiere auth)
148
+ 5. **Body**: JSON
149
+
150
+ ## Ejemplo de Body
151
+ ```json
152
+ {
153
+ "event_type": "order.created",
154
+ "data": {
155
+ "order_id": "{{ $json.order_id }}",
156
+ "customer_email": "{{ $json.email }}",
157
+ "total": {{ $json.total }}
158
+ }
159
+ }
160
+ ```
161
+
162
+ ## Flujo de Procesamiento
163
+
164
+ 1. Se valida el payload
165
+ 2. Se encola para procesamiento async
166
+ 3. Se retorna inmediatamente con request_id
167
+ 4. El procesamiento ocurre en background
168
+
169
+ ## Para verificar estado
170
+
171
+ GET /webhooks/status/{request_id}
172
+ """
173
+ request_id = str(uuid4())
174
+
175
+ # Validar evento
176
+ if payload.event_type != "order.created":
177
+ raise HTTPException(
178
+ status_code=400,
179
+ detail={
180
+ "success": False,
181
+ "error": f"Expected event_type 'order.created', got '{payload.event_type}'",
182
+ "error_code": "INVALID_EVENT_TYPE"
183
+ }
184
+ )
185
+
186
+ # Procesar en background para respuesta rápida (< 3s para n8n)
187
+ background_tasks.add_task(
188
+ process_order_async,
189
+ request_id=request_id,
190
+ order_data=payload.data
191
+ )
192
+
193
+ return WebhookResponse(
194
+ success=True,
195
+ message="Order queued for processing",
196
+ request_id=request_id,
197
+ processed_at=datetime.utcnow()
198
+ )
199
+
200
+
201
+ @router.get("/status/{request_id}")
202
+ async def get_webhook_status(request_id: str) -> dict:
203
+ """
204
+ Obtiene el estado de un webhook procesado.
205
+
206
+ Útil para workflows de n8n que necesitan polling.
207
+ """
208
+ status = await get_processing_status(request_id)
209
+
210
+ return {
211
+ "request_id": request_id,
212
+ "status": status.state, # pending, processing, completed, failed
213
+ "result": status.result,
214
+ "error": status.error,
215
+ "completed_at": status.completed_at
216
+ }
217
+ ```
218
+
219
+ ---
220
+
221
+ ## Diseño de APIs para n8n
222
+
223
+ ### Respuestas Consistentes
224
+ ```python
225
+ from typing import Generic, TypeVar, List, Optional
226
+ from pydantic import BaseModel
227
+
228
+ T = TypeVar('T')
229
+
230
+ class PaginatedResponse(BaseModel, Generic[T]):
231
+ """Respuesta paginada estándar para n8n."""
232
+ items: List[T]
233
+ total: int
234
+ page: int
235
+ page_size: int
236
+ has_more: bool
237
+
238
+ class APIResponse(BaseModel, Generic[T]):
239
+ """Respuesta API estándar."""
240
+ success: bool = True
241
+ data: T
242
+ message: Optional[str] = None
243
+
244
+
245
+ # Uso
246
+ @router.get("/orders", response_model=APIResponse[PaginatedResponse[Order]])
247
+ async def list_orders(
248
+ page: int = 1,
249
+ page_size: int = 20,
250
+ status: Optional[str] = None,
251
+ created_after: Optional[datetime] = None
252
+ ) -> APIResponse[PaginatedResponse[Order]]:
253
+ """
254
+ Lista órdenes con paginación.
255
+
256
+ ## Uso en n8n
257
+
258
+ **HTTP Request Node**:
259
+ - Method: GET
260
+ - URL: {{$env.BACKEND_URL}}/api/v1/orders
261
+ - Query Parameters:
262
+ - page: {{$json.page || 1}}
263
+ - page_size: 50
264
+ - status: pending
265
+
266
+ **Para iterar sobre resultados**:
267
+ Usa el nodo "Split In Batches" después del HTTP Request.
268
+ Accede a items con: {{$json.data.items}}
269
+ """
270
+ orders, total = await order_service.list(
271
+ page=page,
272
+ page_size=page_size,
273
+ status=status,
274
+ created_after=created_after
275
+ )
276
+
277
+ return APIResponse(
278
+ success=True,
279
+ data=PaginatedResponse(
280
+ items=orders,
281
+ total=total,
282
+ page=page,
283
+ page_size=page_size,
284
+ has_more=(page * page_size) < total
285
+ )
286
+ )
287
+ ```
288
+
289
+ ### Filtros Flexibles
290
+ ```python
291
+ from enum import Enum
292
+ from typing import Optional
293
+
294
+ class OrderStatus(str, Enum):
295
+ PENDING = "pending"
296
+ PROCESSING = "processing"
297
+ COMPLETED = "completed"
298
+ CANCELLED = "cancelled"
299
+
300
+ @router.get("/orders/search")
301
+ async def search_orders(
302
+ # Filtros de igualdad
303
+ status: Optional[OrderStatus] = None,
304
+ customer_id: Optional[int] = None,
305
+
306
+ # Filtros de rango
307
+ min_total: Optional[float] = None,
308
+ max_total: Optional[float] = None,
309
+ created_after: Optional[datetime] = None,
310
+ created_before: Optional[datetime] = None,
311
+
312
+ # Búsqueda de texto
313
+ search: Optional[str] = None,
314
+
315
+ # Paginación
316
+ page: int = 1,
317
+ page_size: int = 20,
318
+
319
+ # Ordenamiento
320
+ sort_by: str = "created_at",
321
+ sort_order: str = "desc"
322
+ ):
323
+ """
324
+ Búsqueda avanzada de órdenes.
325
+
326
+ ## Ejemplos de uso en n8n
327
+
328
+ **Órdenes pendientes de hoy**:
329
+ ```
330
+ /orders/search?status=pending&created_after={{$today}}
331
+ ```
332
+
333
+ **Órdenes mayores a $100**:
334
+ ```
335
+ /orders/search?min_total=100&sort_by=total&sort_order=desc
336
+ ```
337
+
338
+ **Buscar por email**:
339
+ ```
340
+ /orders/search?search=customer@example.com
341
+ ```
342
+ """
343
+ pass
344
+ ```
345
+
346
+ ---
347
+
348
+ ## Documentación para n8n
349
+
350
+ ### Template de Documentación de Endpoint
351
+ ```markdown
352
+ # [Nombre del Endpoint]
353
+
354
+ ## Descripción
355
+ [Qué hace este endpoint]
356
+
357
+ ## HTTP Request
358
+
359
+ | Propiedad | Valor |
360
+ |-----------|-------|
361
+ | Method | POST/GET/PUT/DELETE |
362
+ | URL | `{{$env.BACKEND_URL}}/path/to/endpoint` |
363
+ | Content-Type | application/json |
364
+ | Auth | API Key / Bearer Token / None |
365
+
366
+ ## Headers
367
+
368
+ | Header | Valor | Requerido |
369
+ |--------|-------|-----------|
370
+ | Content-Type | application/json | Sí |
371
+ | X-API-Key | {{$env.API_KEY}} | Sí |
372
+
373
+ ## Request Body (para POST/PUT)
374
+
375
+ ```json
376
+ {
377
+ "field1": "value",
378
+ "field2": 123,
379
+ "nested": {
380
+ "subfield": "value"
381
+ }
382
+ }
383
+ ```
384
+
385
+ | Campo | Tipo | Requerido | Descripción |
386
+ |-------|------|-----------|-------------|
387
+ | field1 | string | Sí | Descripción |
388
+ | field2 | number | No | Descripción |
389
+
390
+ ## Response
391
+
392
+ ### Success (200)
393
+ ```json
394
+ {
395
+ "success": true,
396
+ "data": {
397
+ "id": "123",
398
+ "result": "..."
399
+ }
400
+ }
401
+ ```
402
+
403
+ ### Error (400/500)
404
+ ```json
405
+ {
406
+ "success": false,
407
+ "error": "Error message",
408
+ "error_code": "ERROR_CODE"
409
+ }
410
+ ```
411
+
412
+ ## Ejemplo en n8n
413
+
414
+ ![Screenshot del nodo configurado]
415
+
416
+ ### Configuración del nodo HTTP Request:
417
+ 1. Agregar nodo "HTTP Request"
418
+ 2. Method: POST
419
+ 3. URL: `{{$env.BACKEND_URL}}/path`
420
+ 4. Authentication: Header Auth
421
+ 5. Header Name: X-API-Key
422
+ 6. Header Value: {{$env.API_KEY}}
423
+ 7. Body Content Type: JSON
424
+ 8. JSON Parameters:
425
+ ```
426
+ {
427
+ "field1": "{{$json.value}}"
428
+ }
429
+ ```
430
+
431
+ ## Casos de Uso
432
+
433
+ 1. **[Caso 1]**: [Descripción del workflow]
434
+ 2. **[Caso 2]**: [Descripción del workflow]
435
+ ```
436
+
437
+ ---
438
+
439
+ ## Patrones de Integración
440
+
441
+ ### 1. Webhook con Callback
442
+ ```
443
+ ┌─────────────────────────────────────────────────────────────────┐
444
+ │ n8n Workflow │
445
+ │ │
446
+ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────┐ │
447
+ │ │ Trigger │───▶│ HTTP Req │───▶│ Wait │───▶│ Callback │ │
448
+ │ │ │ │ (async) │ │ │ │ Handler │ │
449
+ │ └──────────┘ └──────────┘ └──────────┘ └───────────┘ │
450
+ └──────────────────────┬───────────────────────────────┬─────────┘
451
+ │ │
452
+ ▼ │
453
+ ┌─────────────────────────────────┐ │
454
+ │ Backend │ │
455
+ │ │ │
456
+ │ POST /webhooks/process │ │
457
+ │ - Recibe request │ │
458
+ │ - Inicia proceso largo │ │
459
+ │ - Retorna request_id │ │
460
+ │ │ │
461
+ │ (proceso async...) │ │
462
+ │ │ │
463
+ │ POST callback_url │◀──────────────────┘
464
+ │ - Envía resultado a n8n │
465
+ └─────────────────────────────────┘
466
+ ```
467
+
468
+ ```python
469
+ @router.post("/process-with-callback")
470
+ async def process_with_callback(
471
+ payload: WebhookPayload,
472
+ callback_url: str,
473
+ background_tasks: BackgroundTasks
474
+ ):
475
+ """
476
+ Procesa y notifica a n8n cuando termina.
477
+
478
+ En n8n usar "Wait" node después de este request.
479
+ """
480
+ request_id = str(uuid4())
481
+
482
+ # Procesar en background y hacer callback
483
+ background_tasks.add_task(
484
+ process_and_callback,
485
+ request_id=request_id,
486
+ data=payload.data,
487
+ callback_url=callback_url
488
+ )
489
+
490
+ return {"request_id": request_id, "status": "processing"}
491
+
492
+
493
+ async def process_and_callback(
494
+ request_id: str,
495
+ data: dict,
496
+ callback_url: str
497
+ ):
498
+ """Procesa y notifica resultado."""
499
+ try:
500
+ result = await heavy_processing(data)
501
+
502
+ async with httpx.AsyncClient() as client:
503
+ await client.post(callback_url, json={
504
+ "request_id": request_id,
505
+ "success": True,
506
+ "result": result
507
+ })
508
+ except Exception as e:
509
+ async with httpx.AsyncClient() as client:
510
+ await client.post(callback_url, json={
511
+ "request_id": request_id,
512
+ "success": False,
513
+ "error": str(e)
514
+ })
515
+ ```
516
+
517
+ ### 2. Polling Pattern
518
+ ```python
519
+ @router.get("/jobs/{job_id}")
520
+ async def get_job_status(job_id: str):
521
+ """
522
+ Para n8n, usar con "Wait" + "IF" + loop.
523
+
524
+ ## Workflow en n8n
525
+
526
+ 1. HTTP Request: POST /jobs (crear job)
527
+ 2. Loop Start
528
+ 3. Wait: 5 seconds
529
+ 4. HTTP Request: GET /jobs/{job_id}
530
+ 5. IF: {{$json.status}} == "completed"
531
+ - True: Salir del loop
532
+ - False: Volver a paso 3
533
+ """
534
+ job = await get_job(job_id)
535
+
536
+ return {
537
+ "job_id": job_id,
538
+ "status": job.status, # pending, running, completed, failed
539
+ "progress": job.progress, # 0-100
540
+ "result": job.result if job.status == "completed" else None,
541
+ "error": job.error if job.status == "failed" else None
542
+ }
543
+ ```
544
+
545
+ ### 3. Batch Processing
546
+ ```python
547
+ @router.post("/batch/process")
548
+ async def batch_process(items: List[dict]):
549
+ """
550
+ Procesa múltiples items en una sola llamada.
551
+
552
+ Útil para n8n cuando se procesan muchos items.
553
+ Más eficiente que llamar endpoint individual N veces.
554
+ """
555
+ results = []
556
+ errors = []
557
+
558
+ for i, item in enumerate(items):
559
+ try:
560
+ result = await process_item(item)
561
+ results.append({"index": i, "success": True, "data": result})
562
+ except Exception as e:
563
+ errors.append({"index": i, "success": False, "error": str(e)})
564
+
565
+ return {
566
+ "total": len(items),
567
+ "successful": len(results),
568
+ "failed": len(errors),
569
+ "results": results,
570
+ "errors": errors
571
+ }
572
+ ```
573
+
574
+ ---
575
+
576
+ ## Seguridad
577
+
578
+ ### Autenticación para n8n
579
+ ```python
580
+ from fastapi import Header, HTTPException
581
+
582
+ async def verify_api_key(x_api_key: str = Header(...)):
583
+ """Verifica API key de n8n."""
584
+ if x_api_key != settings.N8N_API_KEY:
585
+ raise HTTPException(status_code=401, detail="Invalid API key")
586
+ return x_api_key
587
+
588
+ @router.post("/webhooks/secure-endpoint")
589
+ async def secure_endpoint(
590
+ payload: WebhookPayload,
591
+ _: str = Depends(verify_api_key)
592
+ ):
593
+ """Endpoint protegido con API key."""
594
+ pass
595
+ ```
596
+
597
+ ### Rate Limiting
598
+ ```python
599
+ from slowapi import Limiter
600
+ from slowapi.util import get_remote_address
601
+
602
+ limiter = Limiter(key_func=get_remote_address)
603
+
604
+ @router.post("/webhooks/rate-limited")
605
+ @limiter.limit("100/minute")
606
+ async def rate_limited_endpoint(request: Request, payload: WebhookPayload):
607
+ """Endpoint con rate limiting."""
608
+ pass
609
+ ```
610
+
611
+ ---
612
+
613
+ ## Checklist de Integración
614
+
615
+ ### Antes de crear endpoint para n8n
616
+ - [ ] Definir schema de request/response
617
+ - [ ] Documentar ejemplos de payload
618
+ - [ ] Implementar manejo de errores consistente
619
+ - [ ] Agregar logging apropiado
620
+ - [ ] Considerar timeout de n8n (< 60s para sync)
621
+
622
+ ### Después de implementar
623
+ - [ ] Probar con n8n local
624
+ - [ ] Documentar en `automations/docs/`
625
+ - [ ] Crear workflow de ejemplo
626
+ - [ ] Agregar a colección de Postman/Insomnia
627
+
628
+ ---
629
+
630
+ ## ✅ Checklist de Validación (n8n Integration)
631
+
632
+ ### Webhook/Endpoint
633
+ - [ ] Schema de request/response definido con Pydantic
634
+ - [ ] Ejemplos de payload documentados
635
+ - [ ] Errores retornan `{ success: false, error, error_code }`
636
+ - [ ] Respuesta en < 60 segundos (o usar async + callback)
637
+
638
+ ### Seguridad
639
+ - [ ] API Key o auth header configurado
640
+ - [ ] Rate limiting implementado
641
+ - [ ] Validación de inputs
642
+
643
+ ### Testing
644
+ - [ ] Probado con n8n local (HTTP Request node)
645
+ - [ ] Workflow de ejemplo creado
646
+ - [ ] Happy path + error cases testeados