FCS-dev
Se migró la configuración de alertas Telegram desde una variable de entorno global () hacia campos propios del modelo en la base de datos. Cada usuario configura su propio bot token, chat ID y activación de alertas desde el panel web.
6112db7
# API.md — Referencia general PolySignal Backend
Base URL (dev): `http://localhost:7860`
Base URL (prod, HF Spaces): misma URL que el frontend (mismo origen).
---
## Arranque rápido
```bash
cd backend/
npm install
npm run db:migrate # solo primera vez
npm run db:seed # crea usuarios de prueba
npm run dev # http://localhost:7860
```
Usuarios de prueba: `admin@polysignal.test / Admin123!` y `user@polysignal.test / User123!`
---
## Autenticación
El API usa JWT Bearer. Para obtener un token:
```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')
```
Enviarlo en cada request protegido:
```
Authorization: Bearer <token>
```
---
## Endpoints
### Públicos (sin auth)
| Método | Ruta | Descripción | Doc |
|---|---|---|---|
| `GET` | `/api/v1/health` | Sanity check | [AUTH.md](AUTH.md) |
| `POST` | `/api/v1/auth/login` | Login → JWT | [AUTH.md](AUTH.md) |
| `GET` | `/api/v1/markets` | Lista mercados paginada | [MARKETS.md](MARKETS.md) |
| `GET` | `/api/v1/markets/:id` | Detalle de mercado | [MARKETS.md](MARKETS.md) |
| `GET` | `/api/v1/markets/:id/signal` | Señal AI del mercado | [SIGNALS.md](SIGNALS.md) |
### Protegidos (requieren `Authorization: Bearer <token>`)
| Método | Ruta | Descripción | Doc |
|---|---|---|---|
| `GET` | `/api/v1/auth/me` | Perfil del usuario | [AUTH.md](AUTH.md) |
| `POST` | `/api/v1/positions` | Abrir posición | [POSITIONS.md](POSITIONS.md) |
| `GET` | `/api/v1/positions` | Listar posiciones | [POSITIONS.md](POSITIONS.md) |
| `DELETE` | `/api/v1/positions/:id` | Cerrar posición | [POSITIONS.md](POSITIONS.md) |
| `POST` | `/api/v1/watchlist` | Añadir a watchlist | [WATCHLIST.md](WATCHLIST.md) |
| `GET` | `/api/v1/watchlist` | Listar watchlist | [WATCHLIST.md](WATCHLIST.md) |
| `DELETE` | `/api/v1/watchlist/:marketId` | Eliminar de watchlist | [WATCHLIST.md](WATCHLIST.md) |
| `GET` | `/api/v1/alerts` | Historial de alertas | [ALERTS.md](ALERTS.md) |
---
## Contrato de respuesta
Todas las respuestas siguen el mismo envelope:
```json
// éxito
{ "ok": true, "data": <payload>, "meta": { ...opcional } }
// error
{ "ok": false, "error": { "code": "ERROR_CODE", "message": "...", "details": [...] } }
```
Códigos HTTP: `200` lectura · `201` creación · `204` borrado · `400` validación · `401` no autenticado · `404` no encontrado · `409` conflicto · `429` rate limit · `500` server error.
---
## Rate limiting
- **Global:** 200 req / 15 min / IP
- **`POST /auth/login`:** 5 intentos / 15 min / IP
Headers de respuesta: `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset`.
---
## WebSocket (Socket.io)
Conectar al mismo host que el backend:
```js
import { io } from 'socket.io-client';
const socket = io('http://localhost:7860');
```
| Evento | Frecuencia | Descripción | Doc |
|---|---|---|---|
| `market_update` | cada 30s | Precio actualizado de un mercado | [MARKETS.md](MARKETS.md) |
| `ai_signal` | cada 5 min | Nueva señal AI generada | [SIGNALS.md](SIGNALS.md) |
| `price_alert` | cuando se dispara | Alerta de precio threshold | [ALERTS.md](ALERTS.md) |
---
## Importar en Insomnia / Postman
Ver [`insomnia-collection.json`](insomnia-collection.json) — export v4 listo para importar en Insomnia.
Pasos:
1. Abrir Insomnia → Import → File
2. Seleccionar `backend/docs/insomnia-collection.json`
3. Configurar variable de entorno `base_url = http://localhost:7860`
4. Ejecutar `POST /auth/login` y copiar el token a la variable `token`
---
## Variables de entorno completas
Ver [`backend/.env.example`](../.env.example) para la plantilla completa.
| Variable | Obligatoria | Descripción |
|---|---|---|
| `PORT` | Sí | Puerto del servidor (7860 para HF Spaces) |
| `DATABASE_URL` | Sí | Path SQLite: `file:./polysignal.db` |
| `JWT_SECRET` | Sí | Mínimo 32 chars |
| `JWT_EXPIRES_IN` | No | Default `1h` |
| `BCRYPT_ROUNDS` | No | Default `10` |
| `CORS_ORIGIN` | No | Default `http://localhost:5173` |
| `LOG_LEVEL` | No | Default `info` |
| `HF_TOKEN` | No | HuggingFace (señales AI reales) |
| `OPENROUTER_API_KEY` | No | Fallback LLM |
| `FINNHUB_API_KEY` | No | Noticias para señales |