# dynatrace-ai-chat — Guía Completa de Integración

## Qué es esto

Un chat web con IA (Claude) que se conecta en tiempo real a un tenant Dynatrace para consultar problemas, métricas, entidades y eventos usando las APIs de Dynatrace. La IA NO inventa datos — siempre consulta Dynatrace antes de responder.

Incluye AI Observability: cada conversación, llamada LLM y tool call se envía como traces y métricas a Dynatrace vía OTLP.

---

## Arquitectura

```
┌─────────────┐     SSE      ┌──────────────┐   Claude API   ┌───────────┐
│  Browser     │◄────────────►│  server.js   │◄──────────────►│ Anthropic │
│  (chat UI)   │              │  (Express)   │                └───────────┘
└─────────────┘              │              │
                              │  dynatrace-  │   API v2 + DQL  ┌───────────┐
                              │  tools.js    │◄────────────────►│ Dynatrace │
                              └──────────────┘   OTLP traces   │  Tenant   │
                                                 OTLP metrics  └───────────┘
```

**Flujo de una pregunta:**
1. Usuario escribe pregunta en el chat
2. Frontend envía POST /api/chat con SSE (Server-Sent Events)
3. server.js envía la pregunta a Claude con el system prompt y las 6 tools disponibles
4. Claude decide qué tool usar (get_problems, query_metrics, execute_dql, etc.)
5. server.js ejecuta la tool contra la API de Dynatrace y devuelve el resultado a Claude
6. Claude genera la respuesta final con los datos reales
7. La respuesta se streama al frontend en tiempo real
8. Todo queda registrado como traces en Dynatrace (AI Observability)

---

## Estructura de archivos

```
dynatrace-ai-chat/
├── config.js              # PERSONALIZAR: bots, branding, modelo LLM
├── server.js              # NO TOCAR: Express + SSE + Claude + OTEL
├── dynatrace-tools.js     # NO TOCAR: 6 tools genéricas Dynatrace
├── package.json           # Dependencias Node.js
├── .env                   # CONFIGURAR: credenciales (nunca commitear)
├── .env.example           # Template de .env
├── public/
│   ├── index.html         # NO TOCAR: shell HTML (se auto-genera)
│   ├── chat-widget.js     # NO TOCAR: frontend dinámico
│   └── styles.css         # NO TOCAR: CSS con variables
├── prompts/               # PERSONALIZAR: system prompts por bot
│   ├── infrastructure.txt
│   └── business.txt
└── examples/
    └── wom/               # Ejemplo WOM Chile como referencia
        ├── config.js
        └── prompts/
            ├── infrastructure.txt
            └── business.txt
```

### Resumen: qué tocar y qué no

| Archivo | Modificar? | Para qué |
|---------|-----------|----------|
| `.env` | **SI** | Credenciales Dynatrace + Anthropic |
| `config.js` | **SI** | Bots, branding, modelo, observabilidad |
| `prompts/*.txt` | **SI** | System prompts con contexto del cliente |
| `server.js` | NO | Servidor genérico |
| `dynatrace-tools.js` | NO | Tools Dynatrace genéricas |
| `public/*` | NO | Frontend auto-configurable |

---

## Paso 1: Requisitos previos

### Software
- Node.js 18+ (recomendado 22)
- npm

### Credenciales necesarias

| Credencial | Dónde obtener | Para qué |
|-----------|---------------|----------|
| ANTHROPIC_API_KEY | https://console.anthropic.com/settings/keys | Llamar a Claude |
| DYNATRACE_API_TOKEN | Dynatrace > Settings > Access Tokens | API v2 (problems, entities, events) |
| OAUTH_CLIENT_ID + SECRET | Dynatrace > Account Management > OAuth clients | DQL/Grail queries |
| DT_ACCOUNT_URN | Dynatrace > Account Management | OAuth resource |
| DT_OTLP_TOKEN | Dynatrace > Settings > Access Tokens | Enviar traces/métricas de AI Obs |

### Scopes del API Token (DYNATRACE_API_TOKEN)
- `problems.read`
- `entities.read`
- `events.read`
- `metrics.read`

### Scopes del OTLP Token (DT_OTLP_TOKEN)
- `openTelemetryTrace.ingest`
- `metrics.ingest`

### Scopes del OAuth Client
- `storage:metrics:read`
- `storage:events:read`
- `storage:logs:read`
- `storage:buckets:read`
- `storage:entities:read`
- `storage:spans:read`
- `storage:smartscape:read`
- `app-engine:apps:run`
- `document:documents:read`
- `settings:objects:read`

---

## Paso 2: Configurar .env

```bash
cp .env.example .env
```

Completar todos los campos:

```env
# Claude
ANTHROPIC_API_KEY=sk-ant-api03-...

# Dynatrace Tenant
DYNATRACE_URL=https://TENANT_ID.live.dynatrace.com
DYNATRACE_APPS_URL=https://TENANT_ID.apps.dynatrace.com

# API Token
DYNATRACE_API_TOKEN=dt0c01...

# OAuth (para DQL)
OAUTH_CLIENT_ID=dt0s02...
OAUTH_CLIENT_SECRET=dt0s02...
DT_ACCOUNT_URN=urn:dtaccount:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

# OTLP (AI Observability) — opcional, si no se pone no se envían traces
DT_OTLP_TOKEN=dt0c01...

# Puerto
PORT=3000
```

---

## Paso 3: Personalizar config.js

### BRANDING — Nombre y colores

```js
export const BRANDING = {
  // HTML permitido (se inyecta en el header)
  title: 'Mi Empresa × Dynatrace AI',

  // Texto plano en el footer
  footer: 'Demo IA + Dynatrace | Powered by Claude',

  // Variables CSS (tema oscuro por defecto)
  colors: {
    primary: '#6366f1',       // Botones, acentos
    secondary: '#14b8a6',     // Tool indicators
    background: '#0f172a',    // Fondo
    surface: '#1e293b',       // Paneles
    border: '#334155',        // Bordes
    text: '#e2e8f0',          // Texto principal
    textMuted: '#94a3b8',     // Texto secundario
  },
};
```

### BOTS — Paneles de chat

Puedes definir 1, 2, 3 o más bots. Cada uno tiene su panel en la UI y su propio system prompt.

```js
export const BOTS = [
  {
    id: 'mi_bot',                    // ID único (sin espacios)
    name: 'Nombre del Bot',          // Título en el panel
    subtitle: 'Descripción corta',   // Subtítulo
    icon: '&#9881;',                 // Icono HTML (emoji o HTML entity)
    
    // Gradiente del header del panel (CSS)
    headerGradient: 'rgba(239, 68, 68, 0.1), rgba(249, 115, 22, 0.05)',
    headerBorder: 'rgba(239, 68, 68, 0.2)',
    
    // Colores del botón enviar (CSS gradient stops)
    buttonGradient: ['#ef4444', '#f97316'],
    buttonGradientHover: ['#dc2626', '#ea580c'],
    
    // Placeholder del input
    placeholder: 'Ej: ¿Hay problemas activos?',
    
    // Botones de sugerencia (aparecen antes del primer mensaje)
    suggestions: [
      { label: 'Texto corto del botón', text: 'Pregunta completa que se envía' },
      { label: 'Otro botón', text: 'Otra pregunta' },
    ],
    
    // Ruta al archivo de system prompt
    promptFile: path.join(__dirname, 'prompts', 'mi_bot.txt'),
  },
  // ... más bots
];
```

**Iconos útiles:**
- ⚙ `&#9881;` — Infraestructura
- 📈 `&#128200;` — Negocio/Métricas
- 🛡 `&#128737;` — Seguridad
- 🔍 `&#128269;` — Análisis
- 💻 `&#128187;` — Aplicaciones
- 🌐 `&#127760;` — Red/Web

### LLM — Modelo Claude

```js
export const LLM = {
  model: 'claude-haiku-4-5-20251001',  // Modelo a usar
  maxTokens: 2048,                      // Max tokens por respuesta
  maxToolLoops: 10,                     // Max iteraciones tool_use
  maxHistory: 20,                       // Mensajes en memoria por conversación
};
```

**Modelos disponibles (verificar con tu API key):**
- `claude-haiku-4-5-20251001` — Rápido, económico, bueno para demos
- `claude-sonnet-4-6-20250514` — Equilibrado (requiere plan con acceso)
- `claude-opus-4-6-20250514` — Máxima calidad (requiere plan con acceso)

### OBSERVABILITY — Traces a Dynatrace

```js
export const OBSERVABILITY = {
  serviceName: 'NombreCliente-Chatbot-IA',  // Aparece en Dynatrace
  metricsIntervalMs: 15000,                  // Cada cuánto envía métricas
  enabled: true,                             // false para desactivar
};
```

---

## Paso 4: Escribir los System Prompts

Esta es la parte más importante. Los prompts definen la personalidad, conocimiento y comportamiento del bot.

### Archivo: prompts/[bot_id].txt

El nombre del archivo debe coincidir con lo que dice `promptFile` en config.js.

### Estructura recomendada

```txt
Eres [ROL ESPECÍFICO] para [NOMBRE CLIENTE]. [UNA FRASE DE CONTEXTO].

Responde siempre en español.

ESTILO DE COMUNICACIÓN:
- Habla de forma directa y natural
- NUNCA digas "Te voy a consultar" — simplemente consulta sin anunciar
- Ve directo al dato, sin rodeos
- Cuando consultes herramientas, no narres lo que estás haciendo — solo muestra el resultado
- [Agregar reglas de tono específicas del cliente si aplica]

CONTEXTO DE [CLIENTE]:
- [Descripción de la infraestructura/aplicaciones/servicios]
- [Qué monitorea Dynatrace en este cliente]
- [Datos relevantes: cantidad de hosts, servicios, tecnologías]

REGLA FUNDAMENTAL:
- SIEMPRE usa las herramientas para consultar datos REALES de Dynatrace antes de responder
- NUNCA inventes datos, estimaciones ni rangos genéricos
- Si no tienes datos, di "no hay datos disponibles"
- NUNCA respondas basándote en conocimiento general
- Cada respuesta DEBE estar respaldada por una consulta real a Dynatrace

MÉTRICAS DISPONIBLES:
[Listar las métricas que existen en el tenant. Esto es CRÍTICO para que
Claude sepa qué consultar. Sin esto, Claude adivinará nombres de métricas
que pueden no existir.]

- builtin:host.cpu.usage → CPU de hosts
- builtin:service.response.time → Latencia de servicios
- builtin:service.errors.total.rate → Tasa de errores
- [custom.metrica.del.cliente] → [descripción]
Dimensiones: host.name, service.name, etc.

CÓMO CONSULTAR:
- Para problemas activos: get_problems (timeframe="now-2h" o "now-24h")
- Para métricas: query_metrics con metricSelector="builtin:host.cpu.usage"
- Para listar métricas: list_metrics con filter="builtin:host."
- Para entidades: get_entities con entitySelector='type("HOST")'
- Para DQL avanzado: execute_dql con query="fetch logs | filter loglevel == \"ERROR\" | limit 20"
- Para eventos: get_events

FORMATO DE RESPUESTA:
- Incluye datos numéricos reales en cada respuesta
- Usa tablas cuando presentes múltiples datos
- Sé conciso pero técnicamente preciso
- [Agregar reglas de formato específicas]
```

### Tips para buenos prompts

1. **Listar métricas explícitamente** — Si no le dices a Claude qué métricas existen, va a inventar nombres. Puedes obtener la lista ejecutando `list_metrics` con filter="" desde el chat.

2. **Dar contexto del negocio** — Si el bot es de negocio, explica qué significan las métricas en términos de impacto a clientes/revenue.

3. **Incluir umbrales** — "CPU > 80% es preocupante, > 95% es crítico" ayuda a Claude a interpretar los datos.

4. **Definir el tono** — "Habla como ingeniero chileno" vs "Habla como ejecutivo formal" cambia completamente la experiencia.

5. **No repetir lo obvio** — No necesitas explicar cómo funcionan las herramientas internamente. Claude ya sabe usarlas por las definiciones de las tools.

---

## Paso 5: Instalar y levantar

```bash
# Instalar dependencias
npm install

# Levantar
npm start

# Abrir en navegador
# http://localhost:3000
```

---

## Paso 6: Verificar

1. Abrir http://localhost:3000
2. Verificar que el badge dice "Dynatrace: 6 tools" (verde)
3. Enviar una pregunta simple: "¿Hay problemas activos?"
4. Verificar en la consola del servidor que aparecen logs de tools ejecutándose
5. Si configuraste OTLP, verificar en Dynatrace > AI Observability que aparecen traces

---

## Tools Dynatrace incluidas (6)

Estas tools son genéricas y funcionan con cualquier tenant. NO necesitas modificarlas.

### 1. get_problems
Consulta problemas detectados por Davis AI.
- Input: `timeframe` (ej: "now-2h", "now-24h", "now-7d")
- Output: lista de problemas con severidad, impacto, causa raíz, entidades afectadas

### 2. query_metrics
Consulta una métrica específica vía DQL.
- Input: `metricSelector` (ej: "builtin:host.cpu.usage"), `from`, `to`
- Output: registros con valores y timestamps

### 3. list_metrics
Lista métricas disponibles en el tenant.
- Input: `filter` (ej: "builtin:host.", "custom.", "")
- Output: lista de metric keys con conteo

### 4. get_entities
Obtiene entidades monitoreadas.
- Input: `entitySelector` (ej: `type("HOST")`, `type("SERVICE")`, `type("PROCESS_GROUP")`)
- Output: lista de entidades con propiedades y tags

### 5. get_events
Obtiene eventos recientes.
- Input: `from`, `to`
- Output: lista de eventos con tipo, título, timestamp

### 6. execute_dql
Ejecuta una consulta DQL libre contra Grail. La más poderosa.
- Input: `query` (sintaxis DQL completa), `from`, `to`, `limit`
- Output: registros crudos

**Ejemplos de DQL útiles:**
```
// Logs de error
fetch logs | filter loglevel == "ERROR" | limit 20

// Top servicios por latencia
fetch dt.entity.service | fields entity.name, entity.detected_name | limit 20

// Métricas custom con dimensiones
timeseries avg(builtin:host.cpu.usage), by:{dt.entity.host}

// Spans lentos
fetch spans | filter duration > 5000000000 | sort duration desc | limit 10
```

---

## Ejemplo completo: Configuración para banco

### config.js (fragmento BOTS)
```js
export const BOTS = [
  {
    id: 'operaciones',
    name: 'Centro de Operaciones',
    subtitle: 'Core bancario, canales digitales, integraciones',
    icon: '&#128187;',
    headerGradient: 'rgba(34, 197, 94, 0.1), rgba(16, 185, 129, 0.05)',
    headerBorder: 'rgba(34, 197, 94, 0.2)',
    buttonGradient: ['#22c55e', '#10b981'],
    buttonGradientHover: ['#16a34a', '#059669'],
    placeholder: 'Ej: ¿Cómo está el core bancario?',
    suggestions: [
      { label: 'Problemas activos', text: '¿Hay problemas activos?' },
      { label: 'Core bancario', text: '¿Cómo está el core bancario?' },
      { label: 'Canales digitales', text: '¿Cómo están los canales digitales?' },
      { label: 'Integraciones', text: '¿Hay errores en las integraciones?' },
    ],
    promptFile: path.join(__dirname, 'prompts', 'operaciones.txt'),
  },
];
```

### prompts/operaciones.txt
```txt
Eres el ingeniero de guardia del Centro de Operaciones TI de Banco Example.
Tu rol es monitorear la salud de los sistemas críticos usando Dynatrace.

Responde en español, de forma directa y técnica.

ESTILO:
- Habla como un ingeniero de operaciones bancario
- Prioriza siempre los sistemas críticos (core, pagos, canales)
- Si hay problemas, sugiere acciones inmediatas
- Usa formato ejecutivo: estado, detalle, acción recomendada

CONTEXTO DEL BANCO:
- Core bancario: AS400 + middleware Java (WebSphere)
- Canales: App móvil (iOS/Android), Web transaccional, ATMs
- Integraciones: API Gateway (Kong), ESB (MuleSoft), SII, SBIF
- Infraestructura: 45 hosts, 120+ servicios, 3 clusters K8s
- Bases de datos: Oracle RAC, PostgreSQL, Redis

REGLA FUNDAMENTAL:
- SIEMPRE consulta Dynatrace antes de responder
- NUNCA inventes datos
- Si no hay datos, di "no hay datos disponibles"

MÉTRICAS CLAVE:
- builtin:host.cpu.usage → CPU hosts
- builtin:host.mem.usage → Memoria hosts
- builtin:service.response.time → Latencia servicios
- builtin:service.errors.total.rate → Tasa de errores
- builtin:service.requestCount.total → Volumen de requests
- builtin:tech.generic.cpu.usage → CPU por tecnología
Dimensiones: dt.entity.host, dt.entity.service

UMBRALES CRÍTICOS:
- CPU > 85%: alerta, > 95%: crítico
- Latencia core > 500ms: alerta, > 2s: crítico
- Error rate > 1%: alerta, > 5%: crítico
- Disponibilidad < 99.9%: crítico para canales digitales
```

---

## Troubleshooting

| Problema | Causa | Solución |
|----------|-------|----------|
| 404 en modelo | API key sin acceso o modelo deprecado | Verificar modelo con test, cambiar en config.js |
| OAuth error | Client credentials incorrectas | Verificar OAUTH_CLIENT_ID, SECRET y URN en .env |
| DQL vacío | Métricas no existen | Usar list_metrics para descubrir métricas del tenant |
| OTLP no llega | Token sin scopes | Verificar DT_OTLP_TOKEN tiene ingest scopes |
| Puerto ocupado | Otro proceso en 3000 | Cambiar PORT en .env |
| "No hay datos" | Prompt no lista métricas | Agregar métricas reales del tenant al prompt |

---

## Checklist de integración nuevo cliente

- [ ] Obtener credenciales Dynatrace (API Token, OAuth, OTLP)
- [ ] Obtener o crear API key de Anthropic
- [ ] Configurar .env con todas las credenciales
- [ ] Definir cuántos bots y sus roles en config.js
- [ ] Conectarse al tenant y ejecutar list_metrics para descubrir métricas
- [ ] Escribir prompts con contexto del cliente y métricas reales
- [ ] Ajustar branding (nombre, colores) en config.js
- [ ] npm install && npm start
- [ ] Probar cada bot con preguntas simples
- [ ] Verificar que las respuestas usan datos reales (no inventados)
- [ ] Verificar AI Observability en Dynatrace (si aplica)
