# MANG Service - Multi-Agent News Geolocalizer Microservicio Go para agregación de noticias RSS con geolocalización automática. ## Estado del Proyecto - ✅ **T1**: Worker RSS + API REST + SQLite (completado) - ✅ **T2**: Geolocalización ligera con diccionario local (completado) ## Features ### T1 - Fundación - Worker RSS que ingesta noticias cada 5 minutos - Base de datos SQLite persistente - API REST `/news` con últimas 50 noticias - Health check en `/health` - Deduplicación por link ### T2 - Geolocalización - Diccionario local de 29 ubicaciones (países y ciudades) - Worker que procesa noticias sin coordenadas cada 90s - Matching case-insensitive de keywords en títulos - Enriquecimiento automático con lat/lon/location_name - Noticias geolocalizadas disponibles vía API ## Quick Start ```bash # Compilar go build -o mang-service # Ejecutar export RSS_FEED_URL="https://news.ycombinator.com/rss" ./mang-service # Consultar noticias curl http://localhost:8080/news ``` ## Variables de Entorno | Variable | Default | Descripción | |----------|---------|-------------| | `DB_PATH` | `/data/mang.db` | Ruta de SQLite | | `LOCATIONS_PATH` | `./data/locations.json` | Diccionario de ubicaciones | | `RSS_FEED_URL` | `https://news.ycombinator.com/rss` | Feed RSS | | `PORT` | `8080` | Puerto HTTP | ## Estructura del Proyecto ``` mang-service/ ├── data/ │ └── locations.json # Diccionario keyword→coordenadas ├── db/ │ └── database.go # SQLite + queries ├── handlers/ │ └── news.go # HTTP handlers ├── models/ │ └── news.go # Modelo News + Location ├── workers/ │ ├── rss_ingester.go # Worker RSS (T1) │ ├── geo_enricher.go # Worker geo (T2) │ └── geo_enricher_test.go # Tests ├── main.go # Entry point ├── go.mod # Dependencias ├── T2_README.md # Docs de T2 └── test_t2.sh # Test de integración ``` ## Testing ```bash # Tests unitarios go test -v ./workers # Test de integración T2 ./test_t2.sh ``` ## API ### GET /news Devuelve últimas 50 noticias ordenadas por fecha de publicación. **Response:** ```json [ { "id": 1, "title": "Terremoto en Japón causa daños", "link": "https://...", "published_at": "2026-04-05T13:00:00Z", "created_at": "2026-04-05T13:05:00Z", "latitude": 36.2048, "longitude": 138.2529, "location_name": "Japón" } ] ``` Noticias sin geolocalización omiten campos `latitude`, `longitude`, `location_name`. ### GET /health Health check simple. **Response:** `200 OK` + `{"status": "ok"}` ## Dependencias - `github.com/mmcdole/gofeed` - Parser RSS/Atom - `modernc.org/sqlite` - SQLite puro Go - Go 1.21+ ## Logs ``` [RSS Ingester] Starting (interval: 5m0s, feed: https://...) [RSS Ingester] Fetched 30 items, inserted 25 new [GeoEnricher] Loaded 29 locations from ./data/locations.json [GeoEnricher] Processing 25 news without location [GeoEnricher] Enriched news 3 'Madrid acoge...' with location Madrid [GeoEnricher] Enriched 8/25 news with coordinates ``` ## Roadmap - [ ] T3: Detección de duplicados semánticos - [ ] T4: Clustering por ubicación geográfica - [ ] T5: API GraphQL - [ ] T6: Frontend de mapa interactivo --- Desarrollado como parte del factory-flow skill de OpenClaw.