@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,296 @@
1
+ ---
2
+ description: Workflow para testing completo de una aplicación
3
+ level: 2
4
+ personas: [qa-engineer, backend-engineer, frontend-engineer]
5
+ ---
6
+
7
+ # Testing Strategy Workflow
8
+
9
+ Este workflow define la estrategia de testing para el proyecto.
10
+
11
+ ## Pirámide de Tests
12
+
13
+ ```
14
+ ┌───────┐
15
+ │ E2E │ Pocos, lentos, costosos
16
+ /─────────\
17
+ / Integration\ Algunos, moderados
18
+ /───────────────\
19
+ / Unit Tests \ Muchos, rápidos, baratos
20
+ /─────────────────────\
21
+ ```
22
+
23
+ ---
24
+
25
+ ## Unit Tests
26
+
27
+ ### Qué testear
28
+ - Funciones de utilidad
29
+ - Lógica de negocio
30
+ - Transformaciones de datos
31
+ - Validaciones
32
+
33
+ ### Python (pytest)
34
+
35
+ ```python
36
+ # tests/unit/test_utils.py
37
+ import pytest
38
+ from app.utils import calculate_discount
39
+
40
+ class TestCalculateDiscount:
41
+ def test_percentage_discount(self):
42
+ result = calculate_discount(100, percentage=10)
43
+ assert result == 90
44
+
45
+ def test_fixed_discount(self):
46
+ result = calculate_discount(100, fixed=15)
47
+ assert result == 85
48
+
49
+ def test_negative_result_returns_zero(self):
50
+ result = calculate_discount(10, fixed=20)
51
+ assert result == 0
52
+
53
+ @pytest.mark.parametrize("amount,percentage,expected", [
54
+ (100, 10, 90),
55
+ (50, 20, 40),
56
+ (0, 50, 0),
57
+ ])
58
+ def test_parametrized(self, amount, percentage, expected):
59
+ assert calculate_discount(amount, percentage) == expected
60
+ ```
61
+
62
+ ### TypeScript (Jest)
63
+
64
+ ```typescript
65
+ // __tests__/utils.test.ts
66
+ import { formatCurrency } from '../utils';
67
+
68
+ describe('formatCurrency', () => {
69
+ it('formats positive numbers', () => {
70
+ expect(formatCurrency(1234.56)).toBe('$1,234.56');
71
+ });
72
+
73
+ it('handles zero', () => {
74
+ expect(formatCurrency(0)).toBe('$0.00');
75
+ });
76
+
77
+ it('formats negative numbers', () => {
78
+ expect(formatCurrency(-100)).toBe('-$100.00');
79
+ });
80
+ });
81
+ ```
82
+
83
+ ---
84
+
85
+ ## Integration Tests
86
+
87
+ ### Qué testear
88
+ - Endpoints API
89
+ - Database queries
90
+ - Service interactions
91
+ - External API calls (mocked)
92
+
93
+ ### API Tests (pytest + httpx)
94
+
95
+ ```python
96
+ # tests/integration/test_users_api.py
97
+ import pytest
98
+ from httpx import AsyncClient
99
+
100
+ @pytest.fixture
101
+ async def client(app):
102
+ async with AsyncClient(app=app, base_url="http://test") as client:
103
+ yield client
104
+
105
+ class TestUsersAPI:
106
+ async def test_create_user(self, client):
107
+ response = await client.post("/api/users", json={
108
+ "email": "test@example.com",
109
+ "name": "Test User"
110
+ })
111
+
112
+ assert response.status_code == 201
113
+ data = response.json()
114
+ assert data["email"] == "test@example.com"
115
+ assert "id" in data
116
+
117
+ async def test_create_user_duplicate_email(self, client, existing_user):
118
+ response = await client.post("/api/users", json={
119
+ "email": existing_user.email,
120
+ "name": "Another User"
121
+ })
122
+
123
+ assert response.status_code == 409
124
+ ```
125
+
126
+ ### Database Tests
127
+
128
+ ```python
129
+ # tests/integration/test_user_repository.py
130
+ class TestUserRepository:
131
+ async def test_create_and_find(self, db_session):
132
+ repo = UserRepository(db_session)
133
+
134
+ # Create
135
+ user = await repo.create(UserCreate(email="test@example.com"))
136
+
137
+ # Find
138
+ found = await repo.get_by_email("test@example.com")
139
+
140
+ assert found is not None
141
+ assert found.id == user.id
142
+ ```
143
+
144
+ ---
145
+
146
+ ## E2E Tests
147
+
148
+ ### Qué testear
149
+ - User flows críticos
150
+ - Happy paths principales
151
+ - Flujos de autenticación
152
+
153
+ ### Playwright
154
+
155
+ ```typescript
156
+ // e2e/login.spec.ts
157
+ import { test, expect } from '@playwright/test';
158
+
159
+ test.describe('Login flow', () => {
160
+ test('successful login', async ({ page }) => {
161
+ await page.goto('/login');
162
+
163
+ await page.fill('input[name="email"]', 'user@example.com');
164
+ await page.fill('input[name="password"]', 'password123');
165
+ await page.click('button[type="submit"]');
166
+
167
+ await expect(page).toHaveURL('/dashboard');
168
+ await expect(page.locator('text=Welcome')).toBeVisible();
169
+ });
170
+
171
+ test('invalid credentials', async ({ page }) => {
172
+ await page.goto('/login');
173
+
174
+ await page.fill('input[name="email"]', 'wrong@example.com');
175
+ await page.fill('input[name="password"]', 'wrong');
176
+ await page.click('button[type="submit"]');
177
+
178
+ await expect(page.locator('text=Invalid credentials')).toBeVisible();
179
+ });
180
+ });
181
+ ```
182
+
183
+ ---
184
+
185
+ ## Component Tests (Frontend)
186
+
187
+ ```tsx
188
+ // __tests__/UserCard.test.tsx
189
+ import { render, screen, fireEvent } from '@testing-library/react';
190
+ import { UserCard } from '../UserCard';
191
+
192
+ const mockUser = {
193
+ id: '1',
194
+ name: 'John Doe',
195
+ email: 'john@example.com',
196
+ };
197
+
198
+ describe('UserCard', () => {
199
+ it('renders user information', () => {
200
+ render(<UserCard user={mockUser} />);
201
+
202
+ expect(screen.getByText('John Doe')).toBeInTheDocument();
203
+ expect(screen.getByText('john@example.com')).toBeInTheDocument();
204
+ });
205
+
206
+ it('calls onEdit when edit button clicked', () => {
207
+ const onEdit = jest.fn();
208
+ render(<UserCard user={mockUser} onEdit={onEdit} />);
209
+
210
+ fireEvent.click(screen.getByRole('button', { name: /edit/i }));
211
+
212
+ expect(onEdit).toHaveBeenCalledWith(mockUser);
213
+ });
214
+ });
215
+ ```
216
+
217
+ ---
218
+
219
+ ## Code Coverage
220
+
221
+ ### Objetivos
222
+
223
+ | Tipo | Cobertura Mínima |
224
+ |------|------------------|
225
+ | Unit Tests | 80% |
226
+ | Integration | Key paths |
227
+ | E2E | Critical flows |
228
+
229
+ ### Comandos
230
+
231
+ ```bash
232
+ # Python
233
+ pytest --cov=app --cov-report=html
234
+
235
+ # JavaScript
236
+ npm test -- --coverage
237
+ ```
238
+
239
+ ---
240
+
241
+ ## Testing Checklist
242
+
243
+ ```markdown
244
+ ## Para cada PR
245
+ - [ ] Unit tests para nueva lógica
246
+ - [ ] Integration tests para nuevos endpoints
247
+ - [ ] E2E tests si es flujo crítico
248
+ - [ ] Coverage no disminuyó
249
+
250
+ ## Para refactoring
251
+ - [ ] Tests existentes siguen pasando
252
+ - [ ] No cambios a tests (salvo estructura)
253
+
254
+ ## Para bugs
255
+ - [ ] Test que reproduce el bug
256
+ - [ ] Fix hace pasar el test
257
+ - [ ] Regression test agregado
258
+ ```
259
+
260
+ ---
261
+
262
+ ## Test Data
263
+
264
+ ### Fixtures (pytest)
265
+
266
+ ```python
267
+ # conftest.py
268
+ @pytest.fixture
269
+ def sample_user():
270
+ return User(
271
+ id=uuid4(),
272
+ email="test@example.com",
273
+ name="Test User"
274
+ )
275
+
276
+ @pytest.fixture
277
+ async def db_user(db_session, sample_user):
278
+ db_session.add(sample_user)
279
+ await db_session.commit()
280
+ return sample_user
281
+ ```
282
+
283
+ ### Factories
284
+
285
+ ```python
286
+ # tests/factories.py
287
+ import factory
288
+
289
+ class UserFactory(factory.Factory):
290
+ class Meta:
291
+ model = User
292
+
293
+ id = factory.LazyFunction(uuid4)
294
+ email = factory.Sequence(lambda n: f"user{n}@example.com")
295
+ name = factory.Faker("name")
296
+ ```
@@ -0,0 +1,277 @@
1
+ ---
2
+ description: Workflow para integración con APIs de terceros
3
+ level: 2
4
+ personas: [backend-engineer, architect]
5
+ ---
6
+
7
+ # Third-Party Integration Workflow
8
+
9
+ Este workflow guía la integración segura con APIs de terceros.
10
+
11
+ ## Pre-requisitos
12
+
13
+ 1. Documentación de la API externa
14
+ 2. Credenciales de prueba
15
+ 3. Límites de rate conocidos
16
+
17
+ ---
18
+
19
+ ## Fase 1: Análisis
20
+
21
+ ### 1.1 Evaluar la API
22
+
23
+ | Aspecto | Verificar |
24
+ |---------|-----------|
25
+ | Autenticación | API Key, OAuth, Bearer? |
26
+ | Rate Limits | Requests por minuto/hora |
27
+ | Formato | REST, GraphQL, SOAP |
28
+ | Versioning | ¿La versión es estable? |
29
+ | SLA | ¿Garantías de uptime? |
30
+
31
+ ### 1.2 Mapear Endpoints Necesarios
32
+
33
+ ```markdown
34
+ | Endpoint | Método | Uso en nuestro sistema |
35
+ |----------|--------|------------------------|
36
+ | /users | GET | Sync usuarios |
37
+ | /orders | POST | Crear pedidos |
38
+ ```
39
+
40
+ ### 1.3 Diseñar Abstracción
41
+
42
+ ```python
43
+ # Interfaz abstracta para evitar vendor lock-in
44
+ class PaymentProvider(Protocol):
45
+ async def create_payment(self, amount: Decimal) -> PaymentResult:
46
+ ...
47
+
48
+ async def get_payment(self, payment_id: str) -> Payment:
49
+ ...
50
+ ```
51
+
52
+ ---
53
+
54
+ ## Fase 2: Implementación
55
+
56
+ ### 2.1 Configuración
57
+
58
+ ```python
59
+ # config/settings.py
60
+ class ThirdPartySettings(BaseSettings):
61
+ api_key: str
62
+ api_url: str = "https://api.example.com/v1"
63
+ timeout: int = 30
64
+ max_retries: int = 3
65
+
66
+ class Config:
67
+ env_prefix = "THIRD_PARTY_"
68
+ ```
69
+
70
+ ```bash
71
+ # .env
72
+ THIRD_PARTY_API_KEY=sk_test_xxxx
73
+ ```
74
+
75
+ ### 2.2 Cliente HTTP
76
+
77
+ ```python
78
+ # clients/third_party_client.py
79
+ import httpx
80
+ from tenacity import retry, wait_exponential, stop_after_attempt
81
+
82
+ class ThirdPartyClient:
83
+ def __init__(self, settings: ThirdPartySettings):
84
+ self.settings = settings
85
+ self.client = httpx.AsyncClient(
86
+ base_url=settings.api_url,
87
+ headers={"Authorization": f"Bearer {settings.api_key}"},
88
+ timeout=settings.timeout,
89
+ )
90
+
91
+ @retry(
92
+ wait=wait_exponential(min=1, max=10),
93
+ stop=stop_after_attempt(3)
94
+ )
95
+ async def request(self, method: str, path: str, **kwargs):
96
+ response = await self.client.request(method, path, **kwargs)
97
+ response.raise_for_status()
98
+ return response.json()
99
+
100
+ async def get_user(self, user_id: str):
101
+ return await self.request("GET", f"/users/{user_id}")
102
+ ```
103
+
104
+ ### 2.3 Error Handling
105
+
106
+ ```python
107
+ # exceptions/third_party.py
108
+ class ThirdPartyError(Exception):
109
+ """Base error for third party integration"""
110
+
111
+ class ThirdPartyRateLimitError(ThirdPartyError):
112
+ """Rate limit exceeded"""
113
+
114
+ class ThirdPartyAuthError(ThirdPartyError):
115
+ """Authentication failed"""
116
+
117
+ # En el cliente
118
+ async def request(self, method: str, path: str, **kwargs):
119
+ try:
120
+ response = await self.client.request(method, path, **kwargs)
121
+ response.raise_for_status()
122
+ return response.json()
123
+ except httpx.HTTPStatusError as e:
124
+ if e.response.status_code == 429:
125
+ raise ThirdPartyRateLimitError("Rate limit exceeded")
126
+ elif e.response.status_code == 401:
127
+ raise ThirdPartyAuthError("Invalid API key")
128
+ raise ThirdPartyError(f"API error: {e}")
129
+ ```
130
+
131
+ ### 2.4 Caching
132
+
133
+ ```python
134
+ # services/cached_third_party.py
135
+ from functools import lru_cache
136
+ import redis
137
+
138
+ redis_client = redis.Redis()
139
+
140
+ async def get_user_cached(user_id: str) -> dict:
141
+ cache_key = f"third_party:user:{user_id}"
142
+
143
+ # Check cache
144
+ cached = await redis_client.get(cache_key)
145
+ if cached:
146
+ return json.loads(cached)
147
+
148
+ # Fetch from API
149
+ user = await client.get_user(user_id)
150
+
151
+ # Cache for 1 hour
152
+ await redis_client.setex(cache_key, 3600, json.dumps(user))
153
+
154
+ return user
155
+ ```
156
+
157
+ ---
158
+
159
+ ## Fase 3: Testing
160
+
161
+ ### 3.1 Mocking
162
+
163
+ ```python
164
+ # tests/conftest.py
165
+ import respx
166
+
167
+ @pytest.fixture
168
+ def mock_third_party():
169
+ with respx.mock:
170
+ respx.get("https://api.example.com/v1/users/123").mock(
171
+ return_value=httpx.Response(200, json={"id": "123", "name": "Test"})
172
+ )
173
+ yield
174
+ ```
175
+
176
+ ### 3.2 Test Unitarios
177
+
178
+ ```python
179
+ # tests/test_third_party_client.py
180
+ async def test_get_user(mock_third_party):
181
+ client = ThirdPartyClient(settings)
182
+ user = await client.get_user("123")
183
+ assert user["id"] == "123"
184
+
185
+ async def test_rate_limit_handling(mock_third_party):
186
+ respx.get("https://api.example.com/v1/users/123").mock(
187
+ return_value=httpx.Response(429)
188
+ )
189
+
190
+ with pytest.raises(ThirdPartyRateLimitError):
191
+ await client.get_user("123")
192
+ ```
193
+
194
+ ### 3.3 Integration Tests
195
+
196
+ ```python
197
+ # tests/integration/test_third_party_real.py
198
+ @pytest.mark.integration
199
+ @pytest.mark.skipif(not os.getenv("THIRD_PARTY_API_KEY"), reason="No API key")
200
+ async def test_real_api_connection():
201
+ """Test with real API (use sparingly)"""
202
+ client = ThirdPartyClient(settings)
203
+ # Use a safe, idempotent endpoint
204
+ result = await client.health_check()
205
+ assert result["status"] == "ok"
206
+ ```
207
+
208
+ ---
209
+
210
+ ## Fase 4: Monitoring
211
+
212
+ ### 4.1 Métricas
213
+
214
+ ```python
215
+ from prometheus_client import Counter, Histogram
216
+
217
+ third_party_requests = Counter(
218
+ 'third_party_requests_total',
219
+ 'Total requests to third party API',
220
+ ['method', 'endpoint', 'status']
221
+ )
222
+
223
+ third_party_latency = Histogram(
224
+ 'third_party_request_duration_seconds',
225
+ 'Request duration to third party API'
226
+ )
227
+ ```
228
+
229
+ ### 4.2 Alertas
230
+
231
+ ```yaml
232
+ # Prometheus alert rules
233
+ groups:
234
+ - name: third_party
235
+ rules:
236
+ - alert: ThirdPartyHighErrorRate
237
+ expr: |
238
+ rate(third_party_requests_total{status=~"5.."}[5m])
239
+ / rate(third_party_requests_total[5m]) > 0.05
240
+ for: 5m
241
+ annotations:
242
+ summary: "High error rate with third party API"
243
+ ```
244
+
245
+ ---
246
+
247
+ ## Checklist
248
+
249
+ ```markdown
250
+ ## Integration: {nombre}
251
+
252
+ ### Seguridad
253
+ - [ ] Credenciales en variables de entorno
254
+ - [ ] No hardcoded secrets
255
+ - [ ] Credenciales rotables
256
+
257
+ ### Reliability
258
+ - [ ] Retry logic implementado
259
+ - [ ] Timeout configurado
260
+ - [ ] Circuit breaker (opcional)
261
+ - [ ] Fallback strategy
262
+
263
+ ### Performance
264
+ - [ ] Caching implementado
265
+ - [ ] Rate limiting respetado
266
+ - [ ] Connection pooling
267
+
268
+ ### Observability
269
+ - [ ] Logging de requests/responses
270
+ - [ ] Métricas expuestas
271
+ - [ ] Alertas configuradas
272
+
273
+ ### Testing
274
+ - [ ] Unit tests con mocks
275
+ - [ ] Integration tests
276
+ - [ ] Error scenarios cubiertos
277
+ ```