408 lines
No EOL
12 KiB
Markdown
408 lines
No EOL
12 KiB
Markdown
# AGENTS.md - RSS2 Development Guide
|
|
|
|
## 🛠️ Build & Test Commands
|
|
|
|
### Backend (Go)
|
|
```bash
|
|
cd backend && go mod tidy
|
|
cd backend && go build -o ../bin/server ./cmd/server
|
|
cd rss-ingestor-go && go build -o ../bin/rss-ingestor .
|
|
|
|
# Single test
|
|
cd backend && go test ./internal/handlers -v -run TestLogin
|
|
cd backend && go test ./internal/auth -v -run TestGenerateToken
|
|
```
|
|
|
|
### Frontend
|
|
```bash
|
|
cd frontend && npm install
|
|
cd frontend && npm run dev # Development
|
|
cd frontend && npm run build # Production build
|
|
cd frontend && npm test # Run tests
|
|
cd frontend && npm run test:ui # UI mode
|
|
```
|
|
|
|
### Makefile
|
|
```bash
|
|
make build # Build all binaries
|
|
make clean # Remove binaries
|
|
make docker-build # Build Docker images
|
|
```
|
|
|
|
---
|
|
|
|
## 📁 Project Structure
|
|
```
|
|
rss2/
|
|
├── backend/ # Go API server + Workers
|
|
│ ├── cmd/
|
|
│ │ ├── server/main.go # API REST principal (Gin)
|
|
│ │ ├── wiki_worker/main.go # Wikipedia integration
|
|
│ │ ├── qdrant/main.go # Vector indexing worker
|
|
│ │ ├── related/main.go # Related news worker
|
|
│ │ ├── topics/main.go # Country/topic matcher
|
|
│ │ ├── scraper/main.go # Deep scraping worker
|
|
│ │ ├── discovery/main.go # RSS feed discovery
|
|
│ │ └── topics/main.go # Topic matching
|
|
│ └── internal/
|
|
│ ├── handlers/ # HTTP endpoints
|
|
│ ├── models/ # Data models
|
|
│ ├── auth/ # JWT authentication
|
|
│ ├── middleware/ # CORS, Auth middleware
|
|
│ ├── services/ # ML services (Translate, Embeddings, NER, Semantic Search)
|
|
│ ├── db/ # PostgreSQL connection
|
|
│ ├── cache/ # Redis connection
|
|
│ └── config/ # Configuration loading
|
|
├── frontend/ # React + TypeScript + Vite
|
|
│ └── src/
|
|
│ ├── pages/ # Home, News, Search, Admin, Feeds, Stats
|
|
│ ├── components/ # Layout, UI components
|
|
│ └── services/ # API client
|
|
├── workers/ # Python workers
|
|
│ ├── ctranslator_worker.py # NLLB-200 translation (CTranslate2)
|
|
│ ├── ner_worker.py # Spacy NER + Topic extraction
|
|
│ ├── embeddings_worker.py # Sentence transformers embeddings
|
|
│ ├── cluster_worker.py # News clustering
|
|
│ ├── langdetect_worker.py # Language detection
|
|
│ ├── llm_categorizer_worker.py # Ollama LLM categorization
|
|
│ ├── simple_categorizer_worker.py
|
|
│ ├── simple_translator.py
|
|
│ ├── simple_translator_worker.py
|
|
│ ├── translation_worker.py
|
|
│ ├── translation_scheduler.py
|
|
│ └── remote_translator_worker.py # Remote GPU worker via WebSocket
|
|
├── data/ # PostgreSQL, Redis, Qdrant data
|
|
├── models/ # ML models (nllb-ct2)
|
|
├── hf_cache/ # HuggingFace cache
|
|
├── init-db/ # SQL migrations
|
|
├── monitoring/ # Prometheus + Grafana config
|
|
├── rss-ingestor-go/ # RSS crawler (Go)
|
|
└── docker-compose.yml # Full stack orchestration
|
|
```
|
|
|
|
---
|
|
|
|
## 🚀 Servicios del Sistema
|
|
|
|
### Capa de Acceso y API (Puerto 8888)
|
|
| Servicio | Tecnología | Descripción |
|
|
|---------|------------|-------------|
|
|
| **nginx** | Nginx Alpine | Gateway y Proxy Inverso |
|
|
| **rss2_frontend** | React + Vite | Interfaz web responsiva |
|
|
| **backend-go** | Go + Gin | API REST principal |
|
|
|
|
### Ingesta y Descubrimiento (Go)
|
|
| Servicio | Tecnología | Descripción |
|
|
|---------|------------|-------------|
|
|
| **rss-ingestor-go** | Go | Crawler RSS de alto rendimiento |
|
|
| **scraper** | Go | Scraper profundo con sanitización HTML |
|
|
| **discovery** | Go | Agente de descubrimiento de feeds RSS |
|
|
|
|
### Procesamiento de Datos e IA
|
|
| Servicio | Tecnología | Descripción |
|
|
|---------|------------|-------------|
|
|
| **translator** | NLLB-200 (CPU) | Traducción neuronal CTranslate2 |
|
|
| **translator-gpu** | NLLB-200 (GPU) | Traducción acelerada CUDA |
|
|
| **remote-translator** | WebSocket | Worker GPU remoto |
|
|
| **embeddings** | S-Transformers | Generación de vectores semánticos |
|
|
| **ner** | Spacy + BERT | Reconocimiento de entidades (PER, ORG, LOC) |
|
|
| **llm-categorizer** | Ollama/Mistral | Clasificación con modelos de lenguaje |
|
|
| **wiki-worker** | Go | Integración Wikipedia + thumbnails |
|
|
| **topics** | Go | Matcher de países y temas |
|
|
| **related** | Go | Detección de noticias relacionadas |
|
|
| **qdrant-worker** | Go | Vectorización + búsqueda semántica |
|
|
| **cluster** | Python | Agrupación de noticias |
|
|
| **langdetect** | Python | Detección de idioma |
|
|
| **translation-scheduler** | Python | Creador de tareas de traducción |
|
|
|
|
### Capa de Almacenamiento
|
|
| Servicio | Tecnología | Descripción |
|
|
|---------|------------|-------------|
|
|
| **db** | PostgreSQL 18 | Base de datos relacional |
|
|
| **qdrant** | Qdrant | Base de datos vectorial |
|
|
| **redis** | Redis 7 | Cache y colas de mensajes |
|
|
|
|
### Monitoreo
|
|
| Servicio | Tecnología | Descripción |
|
|
|---------|------------|-------------|
|
|
| **prometheus** | Prometheus | Métricas del sistema |
|
|
| **grafana** | Grafana | Dashboard (puerto 3001) |
|
|
| **cadvisor** | cAdvisor | Monitoreo Docker |
|
|
|
|
---
|
|
|
|
## 📝 Code Style Guidelines
|
|
|
|
### Backend (Go)
|
|
|
|
#### Imports
|
|
```go
|
|
package handlers
|
|
|
|
import (
|
|
"net/http"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/rss2/backend/internal/auth"
|
|
"github.com/rss2/backend/internal/models"
|
|
)
|
|
```
|
|
**Order:** Standard → Third-party → Local packages
|
|
**Use:** `goimports` to auto-format
|
|
|
|
#### Naming
|
|
- Packages: lowercase (`handlers`, `services`)
|
|
- Functions/Methods: camelCase (`GetNews`, `CreateUser`)
|
|
- Variables: camelCase (`userId`, `newsList`)
|
|
- Constants: UPPER_SNAKE_CASE (`MaxPageSize`)
|
|
- Types: PascalCase (`NewsResponse`, `User`)
|
|
|
|
#### Error Handling
|
|
```go
|
|
func CreateResource(c *gin.Context) {
|
|
var req CreateRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, models.ErrorResponse{
|
|
Error: "Invalid request",
|
|
Message: err.Error(),
|
|
})
|
|
return
|
|
}
|
|
// ...
|
|
}
|
|
```
|
|
**Always return errors** | **Use `models.ErrorResponse`**
|
|
|
|
#### Database
|
|
```go
|
|
err := db.GetPool().QueryRow(ctx, "SELECT * FROM users WHERE id = $1", id).Scan(&user)
|
|
if err != nil {
|
|
c.JSON(http.StatusNotFound, models.ErrorResponse{Error: "User not found"})
|
|
return
|
|
}
|
|
```
|
|
**Use context** | **Named parameters ($1, $2)**
|
|
|
|
#### Tests
|
|
```go
|
|
func TestLoginInvalidRequest(t *testing.T) {
|
|
router := gin.New()
|
|
router.POST("/auth/login", Login)
|
|
body := []byte(`{}`)
|
|
req, _ := http.NewRequest("POST", "/auth/login", bytes.NewBuffer(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
w := httptest.NewRecorder()
|
|
router.ServeHTTP(w, req)
|
|
if w.Code != http.StatusBadRequest {
|
|
t.Errorf("expected 400, got %d", w.Code)
|
|
}
|
|
}
|
|
```
|
|
**Use `gin.TestMode`** | **Test error paths**
|
|
|
|
---
|
|
|
|
### Frontend (TypeScript + React)
|
|
|
|
#### Imports
|
|
```tsx
|
|
import React, { useState, useEffect } from 'react'
|
|
import { Routes, Route } from 'react-router-dom'
|
|
import { Layout } from './components/layout/Layout'
|
|
import { api } from './services/api'
|
|
```
|
|
**Order:** React → Router → Components → Services → Utils
|
|
|
|
#### Components
|
|
```tsx
|
|
function NewsList() {
|
|
const [news, setNews] = useState<News[]>([])
|
|
const [loading, setLoading] = useState(true)
|
|
const [error, setError] = useState<string | null>(null)
|
|
|
|
useEffect(() => { fetchNews(); }, [])
|
|
|
|
const fetchNews = async () => {
|
|
try {
|
|
const res = await api.get('/news')
|
|
setNews(res.data)
|
|
} catch (err) {
|
|
setError(err.message)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="news-list">
|
|
{loading && <Spinner />}
|
|
{error && <ErrorBanner message={error} />}
|
|
</div>
|
|
)
|
|
}
|
|
```
|
|
|
|
#### Types
|
|
```tsx
|
|
interface News {
|
|
id: number
|
|
title: string
|
|
summary: string
|
|
url: string
|
|
publishedAt: string
|
|
}
|
|
```
|
|
|
|
#### Styling
|
|
- Use Tailwind CSS utility classes
|
|
- Avoid inline styles
|
|
- Use `clsx` for conditional classes
|
|
|
|
#### TypeScript Rules
|
|
- Use `strict: true` mode
|
|
- Avoid `any` - define interfaces
|
|
- Use type guards for narrowing
|
|
- Prefer optional chaining `?.`
|
|
|
|
---
|
|
|
|
## 🔒 Security Guidelines
|
|
|
|
1. **Never commit secrets** - Use `.env` in `.gitignore`
|
|
2. **Validate all inputs** - Use `go-playground/validator`
|
|
3. **Prepared statements** - Prevent SQL injection
|
|
4. **Rate limiting** - On sensitive endpoints
|
|
5. **HTTPS only** - Enforce in production
|
|
|
|
### Variables de Entorno Críticas
|
|
```bash
|
|
POSTGRES_PASSWORD # Contraseña PostgreSQL
|
|
REDIS_PASSWORD # Contraseña Redis
|
|
DB_PASS # Contraseña para workers
|
|
SECRET_KEY # Key JWT
|
|
GRAFANA_PASSWORD # Dashboard password
|
|
```
|
|
|
|
---
|
|
|
|
## 🧪 Testing Best Practices
|
|
|
|
### Backend
|
|
- Test error cases and edge cases
|
|
- Use `gin.TestMode` for HTTP tests
|
|
|
|
### Frontend
|
|
- Test component rendering
|
|
- Test API integration
|
|
- Test error states
|
|
- Use vitest
|
|
|
|
---
|
|
|
|
## 📦 Deployment
|
|
|
|
```bash
|
|
# Generar credenciales seguras
|
|
./pre-deploy.sh --generate
|
|
|
|
# Validar y desplegar
|
|
./pre-deploy.sh
|
|
|
|
# O manualmente
|
|
docker compose up -d
|
|
|
|
# Escalar workers de traducción
|
|
docker compose up -d --scale translator-gpu=4
|
|
```
|
|
|
|
### Escalado de Workers GPU
|
|
```bash
|
|
# 1 worker GPU (8GB+ VRAM)
|
|
docker compose up -d --scale translator-gpu=1
|
|
|
|
# 2 workers GPU (16GB+ VRAM)
|
|
docker compose up -d --scale translator-gpu=2
|
|
|
|
# 4 workers GPU (32GB+ VRAM)
|
|
docker compose up -d --scale translator-gpu=4
|
|
```
|
|
|
|
---
|
|
|
|
## 🔧 Configuración de Workers
|
|
|
|
### Environment Variables Principales
|
|
|
|
| Variable | Descripción | Default |
|
|
|----------|-------------|---------|
|
|
| `DB_HOST` | Host PostgreSQL | localhost |
|
|
| `DB_PORT` | Puerto PostgreSQL | 5432 |
|
|
| `DB_NAME` | Nombre base de datos | rss |
|
|
| `DB_USER` | Usuario PostgreSQL | rss |
|
|
| `DB_PASS` | Contraseña PostgreSQL | - |
|
|
| `TARGET_LANGS` | Idiomas destino | es |
|
|
| `TRANSLATOR_BATCH` | Tamaño de batch | 32 |
|
|
| `CT2_DEVICE` | Dispositivo (cpu/cuda) | cpu |
|
|
| `CT2_COMPUTE_TYPE` | Tipo (int8/float16) | int8 |
|
|
| `NER_BATCH` | Batch NER | 64 |
|
|
| `EMB_BATCH` | Batch embeddings | 64 |
|
|
|
|
---
|
|
|
|
## 📊 Endpoints de API Principales
|
|
|
|
### News
|
|
- `GET /api/news` - Listar noticias (paginado, filtros)
|
|
- `GET /api/news/:id` - Ver noticia con entidades
|
|
- `DELETE /api/news/:id` - Eliminar noticia (admin)
|
|
|
|
### Feeds
|
|
- `GET /api/feeds` - Listar feeds
|
|
- `POST /api/feeds` - Crear feed (auth)
|
|
- `PUT /api/feeds/:id` - Actualizar feed (auth)
|
|
- `DELETE /api/feeds/:id` - Eliminar feed (auth)
|
|
|
|
### Search
|
|
- `GET /api/search?q=...` - Búsqueda texto
|
|
- `GET /api/search?q=...&semantic=true` - Búsqueda semántica
|
|
|
|
### Entities
|
|
- `GET /api/entities?tipo=persona` - Listar entidades (PER, ORG, LOC)
|
|
|
|
### Admin
|
|
- `GET /api/admin/backup` - Backup SQL completo
|
|
- `GET /api/admin/backup/news` - Backup noticias (ZIP)
|
|
- `GET /api/admin/users` - Listar usuarios
|
|
- `POST /api/admin/workers/start` - Iniciar workers traducción
|
|
- `POST /api/admin/workers/stop` - Detener workers traducción
|
|
- `GET /api/admin/workers/status` - Estado de workers
|
|
|
|
### Auth
|
|
- `POST /api/auth/login` - Iniciar sesión
|
|
- `POST /api/auth/register` - Registrarse
|
|
- `GET /api/auth/me` - Usuario actual (auth)
|
|
|
|
### Stats
|
|
- `GET /api/stats` - Estadísticas globales
|
|
|
|
---
|
|
|
|
## 🎯 Capabilities del Sistema
|
|
|
|
1. **Enriquecimiento Wikipedia**: Detecta personas/orgs, descarga biografías e imágenes
|
|
2. **Categorización LLM**: Clasificación con Mistral-7B vía Ollama
|
|
3. **Búsqueda Semántica**: Qdrant vector search con mxbai-embed-large
|
|
4. **Traducción Neuronal**: NLLB-200 (600M-1.3B params) CPU/GPU
|
|
5. **NER**: Spacy es_core_news_lg para entidades nombradas
|
|
6. **Noticias Relacionadas**: Similitud coseno entre embeddings
|
|
7. **Detección de Idioma**: langdetect
|
|
8. **Clustering**: Agrupación automática de noticias
|
|
9. **WebSocket Workers**: Workers GPU remotos conectados por WS
|
|
10. **Backup Automático**: pg_dump con compresión ZIP
|
|
|
|
---
|
|
|
|
## 📖 Documentación Adicional
|
|
|
|
- [README.md](../README.md) - Guía de despliegue completo
|
|
- [DEPLOY.md](./DEPLOY.md) - Instrucciones de producción
|
|
- [SECURITY_GUIDE.md](./SECURITY_GUIDE.md) - Guía de seguridad
|
|
- [QUICKSTART_LLM.md](./QUICKSTART_LLM.md) - Configuración LLM
|
|
- [remote-worker.md](./remote-worker.md) - Workers remotos |