Spaces:
Sleeping
Sleeping
File size: 3,630 Bytes
bce154c 6112db7 bce154c 6112db7 bce154c | 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. El usuario crea un bot en [@BotFather](https://t.me/BotFather) y obtiene su **Bot Token**.
2. El usuario inicia conversación con el bot y obtiene su **Chat ID**.
3. Desde el panel web (botón *Alertas Telegram*), el usuario introduce ambos valores y activa las alertas.
4. Los datos se guardan en el modelo `User` (`telegramBotToken`, `telegramChatId`, `telegramAlertsEnabled`).
Si el usuario no ha configurado su bot token y chat ID, o tiene las alertas desactivadas, 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 |
|