File size: 3,552 Bytes
71b8eb2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | # ALERTS.md — Módulo de alertas
Historial de alertas de precio disparadas por el job `processAlerts`. Las alertas se crean automáticamente cuando `yesPrice >= alertThreshold` en la watchlist del usuario.
**Todos los endpoints requieren `Authorization: Bearer <token>`.**
---
## Endpoints
### `GET /api/v1/alerts`
Lista el historial de alertas del usuario, paginado y ordenado por `sentAt` DESC.
**Query params**
| Param | Tipo | Default | Descripción |
|---|---|---|---|
| `limit` | int (1-100) | `20` | Máximo de resultados |
| `offset` | int | `0` | Paginación por offset |
**Respuesta `200`**
```json
{
"ok": true,
"data": [
{
"id": 4,
"userId": 1,
"marketId": "559677",
"type": "price_threshold",
"message": "<b>Price Alert</b>\nWill Hillary Clinton win the 2028 Democratic presidential nomination?\nYES: 0.8% ≥ threshold 0.1%",
"sentAt": "2026-05-16T09:38:00.033Z",
"market": {
"id": "559677",
"question": "Will Hillary Clinton win the 2028 Democratic presidential nomination?"
}
}
]
}
```
**Campos**
| Campo | Tipo | Descripción |
|---|---|---|
| `id` | int | ID de la alerta |
| `userId` | int | Usuario que la recibió |
| `marketId` | string | Mercado que la disparó |
| `type` | string | Tipo de alerta (`price_threshold`) |
| `message` | string | Mensaje enviado (formato HTML para Telegram) |
| `sentAt` | ISO 8601 | Timestamp de envío |
| `market.question` | string | Pregunta del mercado (para mostrar en UI) |
---
## Flujo de creación
Las alertas **no se crean desde el frontend** — solo se leen. El flujo de creación es:
1. `POST /api/v1/watchlist` con `alertThreshold` → guarda umbral en DB.
2. Job `processAlerts` (cada minuto): evalúa `yesPrice >= alertThreshold` para cada watchlist entry con threshold definido.
3. Si se cumple y no hay alerta reciente (< 5 min): crea `Alert` + envía Telegram + emite `price_alert` por socket.
---
## Socket — evento `price_alert`
**Nombre del evento:** `price_alert`
**Payload**
```json
{
"marketId": "559677",
"type": "price_threshold",
"message": "<b>Price Alert</b>\n..."
}
```
**Uso en el frontend**
```js
socket.on('price_alert', ({ marketId, message }) => {
// mostrar notificación toast
});
```
---
## Integración Telegram
Para recibir alertas vía Telegram:
1. Crear un bot en [@BotFather](https://t.me/BotFather) y obtener el `TELEGRAM_BOT_TOKEN`.
2. El usuario debe iniciar conversación con el bot y obtener su `chatId`.
3. Configurar `telegramChatId` en el registro `User` (actualmente solo vía `prisma studio` o seed).
4. Añadir `TELEGRAM_BOT_TOKEN` al `.env`.
Si `TELEGRAM_BOT_TOKEN` no está configurado o el usuario no tiene `telegramChatId`, el envío se omite silenciosamente (la `Alert` se crea igualmente en DB).
---
## Ejemplos `curl`
```bash
TOKEN=$(curl -s -X POST http://localhost:7860/api/v1/auth/login \
-H 'Content-Type: application/json' \
-d '{"email":"admin@polysignal.test","password":"Admin123!"}' | jq -r '.data.token')
# Listar alertas (últimas 10)
curl -s -H "Authorization: Bearer $TOKEN" \
"http://localhost:7860/api/v1/alerts?limit=10" | jq
# Segunda página
curl -s -H "Authorization: Bearer $TOKEN" \
"http://localhost:7860/api/v1/alerts?limit=10&offset=10" | jq
```
---
## Códigos de error
| HTTP | Código | Cuándo |
|---|---|---|
| `400` | `VALIDATION_ERROR` | Params inválidos (limit > 100) |
| `401` | `UNAUTHORIZED` | Sin token o token inválido |
| `500` | `INTERNAL` | Error inesperado |
|