File size: 5,375 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 131 132 133 134 | # CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
**PolySignal** β a real-time prediction market intelligence dashboard. It fetches market data from Polymarket, enriches it with financial news via Finnhub, runs AI sentiment analysis (ModernFinBERT + Qwen3-8B), and displays signals on an interactive world map. No real trading β pure analysis and virtual simulation. Built for CIFO Barcelona La Violeta Hackathon (May 2026). UI and docs are in **Spanish**, base currency is **Euro (β¬)**.
## Common Commands
```bash
# Development (backend + frontend simultaneously)
npm run dev:all
# Backend only (with --watch)
npm run dev
# Frontend only (Vite @ :5173)
npm run dev:frontend
# Production build (frontend)
npm run build:frontend
# Database
npm run db:migrate # Apply Prisma migrations
npm run db:generate # Regenerate Prisma client
npm run db:studio # Open Prisma Studio GUI
# Docker
docker-compose up --build # Full stack on port 7860
```
Node.js **β₯24.0.0** is required (enforced in package.json engines).
First-time setup:
```bash
npm install
cp .env.example .env # then fill in API keys
npm run db:migrate && npm run db:generate
```
## Architecture
Monorepo with two workspaces: `backend/` (Express 5 + Socket.io) and `frontend/` (Vanilla JS + Vite).
### Backend (`backend/src/`)
Follows a strict **Controller β Service β Repository β Client** layered pattern. Each domain lives in its own directory:
| Directory | Responsibility |
|-----------|---------------|
| `markets/` | Polymarket Gamma API client + sync job |
| `signals/` | AI pipeline (aiPipeline.js) + signals service |
| `finnhub/` | Finnhub news client + service |
| `positions/` | Virtual position simulator + Kelly Criterion sizing |
| `watchlist/` | User-saved markets |
| `alerts/` | Telegram Bot notification delivery |
| `auth/` | JWT + bcryptjs login |
| `socket/` | Socket.io broadcaster |
| `middlewares/` | Auth, validation, error handling, rate limiting |
| `utils/` | Pino logger, HTTP client, Prisma singleton |
Entry points: `src/index.js` (HTTP server + Socket.io setup) β `src/app.js` (Express middleware + route mounting) β `src/scheduler.js` (cron jobs).
Environment/config validated at startup via **Zod** in `src/config.js` β the app crashes fast if required env vars are missing.
### Scheduler Jobs
| Job | Frequency | What it does |
|-----|-----------|-------------|
| `syncMarkets` | 30s | Fetches top 100 active Polymarket markets, broadcasts price changes via Socket.io |
| `generateSignals` | 5m | Runs full AI pipeline on top 20 active markets |
| `updatePositionsPnL` | 30s | Recalculates P&L for open virtual positions |
| `processAlerts` | 1m | Checks watchlist thresholds, fires Telegram alerts |
### AI Signal Pipeline (`signals/aiPipeline.js`)
Three-phase flow with automatic fallbacks:
1. **News filtering** β Finnhub headlines β ModernFinBERT (HF Space) β keep only scores β₯ 0.65, drop neutral
2. **Signal generation** β market data + filtered news β Qwen3-8B (HF Space) β `{ signal, confidence, summary, keyRisk }`
3. **Fallback chain**: HF Space β HF direct inference API β OpenRouter (deepseek-chat) β rule-based (price-trend logic)
### Frontend (`frontend/src/`)
Single-page app with no framework. Key modules:
| File | Role |
|------|------|
| `app.js` | SPA routing, DOM rendering, Socket.io listeners |
| `api.js` | REST client wrapper with JWT token management |
| `map.js` | Leaflet world map (bubble size = volume, color = signal) |
| `charts.js` | Chart.js sparklines + 7-day price history |
| `simulator.js` | Virtual buy/sell logic |
| `filters.js` | Market filtering by category, country, continent, trend |
Vite proxies `/api` and `/socket.io` to backend (`localhost:7860`) during development.
### Database (SQLite via Prisma)
Schema at `backend/prisma/schema.prisma`. Key models:
- `Market` β Polymarket data (prices, volume, category, country code)
- `AISignal` β sentiment signals with confidence and risk summary
- `Position` β virtual trades with entry/exit prices and P&L
- `Watchlist` / `Alert` β user market tracking and Telegram history
- `User` β auth + optional Telegram chat ID
### Real-time Communication
REST API at `/api/v1/*` + WebSocket events via Socket.io:
- `market_update` β price/volume changes
- `ai_signal` β new sentiment signals
- `price_alert` β watchlist threshold triggers
## Deployment Target
The app is designed to run on **HuggingFace Spaces** (port 7860). The Dockerfile uses `node:22-slim`, installs backend deps, copies the frontend `dist/`, runs Prisma generate, and starts the server. The frontend is served as static files by Express in production.
## Key Environment Variables
See `.env.example` for the full list. Critical ones:
```
HF_SPACE_MODERNFINBERT_URL # HuggingFace Space for FinBERT
HF_SPACE_QWEN_URL # HuggingFace Space for Qwen3-8B
HF_TOKEN # HF inference API key (fallback)
OPENROUTER_API_KEY # LLM fallback if HF is down
FINNHUB_API_KEY # News source
TELEGRAM_BOT_TOKEN # Alert delivery
JWT_SECRET # Must be β₯32 characters
PORT=7860 # Required by HF Spaces
DATABASE_URL=file:./backend/prisma/polysignal.db
```
|