Com estic dissenyant Rolsfera: arquitectura real d'un agregador de notícies amb scraping, RSS, IA i automatització
Arquitectura real de Rolsfera, un agregador de notícies amb scraping, RSS i IA. Decisions tècniques, stack, errors i pròxims passos.

Porto mesos construint Rolsfera i encara no he escrit ni una sola línia sobre la seva arquitectura. Suposo que pel mateix que li passa a la majoria de desenvolupadors amb els seus projectes personals: estàs tan ficat en resoldre problemes que documentar es viu com un luxe. Però crec que ja toca.
Rolsfera és un agregador de notícies. No un d’aquells que simplement mostra feeds RSS en una interfície bonica. És un sistema que recull informació de múltiples fonts (RSS, scraping, APIs), la processa, la filtra, la resumeix amb IA i la distribueix a canals com Telegram o X. Tot això amb un grau raonable d’automatització, però amb revisió humana als punts on importa.
Aquest article no és un tutorial pas a pas. És un mapa de les decisions tècniques que he pres, per què les he pres i on m’he equivocat. Si estàs pensant a muntar alguna cosa semblant, espero estalviar-te algunes iteracions.
El problema que intento resoldre
La informació està fragmentada. No és un problema nou, però el 2026 s’ha tornat més absurd que mai. Si vols seguir un tema tècnic necessites revisar blogs, newsletters, RSS, Telegram, X, Reddit, Hacker News i probablement tres o quatre fonts més que depenen del teu nínxol.
Cada font té el seu format, la seva freqüència, el seu nivell de soroll. I el resultat és que passes més temps buscant i filtrant que llegint i processant.
Rolsfera neix d’una frustració real: vull un flux on la informació arribi a mi, filtrada i resumida, sense haver d’obrir quinze pestanyes cada matí.
Però no vull un sistema completament automàtic que publiqui sense supervisió. He vist massa bots de contingut que acaben vomitant escombraries o duplicant notícies irrellevants. La idea és automatitzar la part mecànica (recollir, netejar, resumir) i mantenir el criteri editorial en mans humanes.
Diagrama d’arquitectura
Abans d’entrar en detall, aquest és el flux general del sistema:
┌─────────────────────────────────────────────────────────────────┐
│ FONTS DE DADES │
│ │
│ ┌─────────┐ ┌──────────┐ ┌─────────┐ ┌─────────────┐ │
│ │ RSS │ │ Scraping │ │ APIs │ │ Telegram │ │
│ │ Feeds │ │ (Python) │ │ (REST) │ │ Channels │ │
│ └────┬─────┘ └────┬─────┘ └────┬────┘ └──────┬──────┘ │
│ │ │ │ │ │
└────────┼──────────────┼──────────────┼───────────────┼──────────┘
│ │ │ │
▼ ▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ INGESTA I NORMALITZACIÓ │
│ │
│ n8n (orquestració) + Python (processament) │
│ - Parseig de feeds │
│ - Extracció de contingut │
│ - Deduplicació per URL i hash de contingut │
│ - Normalització de format │
│ │
└────────────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ PROCESSAMENT AMB IA │
│ │
│ - Classificació per categoria │
│ - Generació de resum │
│ - Extracció d'entitats i tags │
│ - Puntuació de rellevància │
│ │
└────────────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ EMMAGATZEMATGE │
│ │
│ PostgreSQL (articles, metadades, estat de publicació) │
│ │
└────────────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ VALIDACIÓ EDITORIAL │
│ │
│ Panell intern: aprovar / descartar / editar abans de publicar │
│ │
└────────────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ DISTRIBUCIÓ │
│ │
│ ┌───────────┐ ┌─────────┐ ┌─────────┐ ┌────────────┐ │
│ │ Telegram │ │ X │ │ Web │ │ Newsletter │ │
│ └───────────┘ └─────────┘ └─────────┘ └────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘No és un diagrama de llibre de text, però reflecteix la realitat. Hi ha quatre capes clares: ingesta, processament, validació i distribució. I entre elles, n8n actua com a cola.
L’stack tècnic
Aquestes són les peces principals i per què les vaig triar:
Python és el llenguatge principal de processament. L’uso per als scrapers, els parsers de RSS, la lògica de deduplicació, la comunicació amb APIs de LLMs i la generació de resums. No cal que justifiqui gaire aquesta decisió: per a tasques d’extracció i processament de dades, Python segueix sent l’opció més pràctica. Les llibreries hi són, la comunitat hi és i el temps de desenvolupament és raonable.
n8n és l’orquestrador. Coordina els fluxos: quan s’executen els scrapers, quan es processen els articles nous, quan s’envien a revisió, quan es publiquen. Podria haver usat Airflow o un sistema de cues propi, però n8n em dona una cosa que per a un projecte personal és valuosa: una interfície visual on veig què ha passat a cada execució sense obrir logs.
# Ejemplo simplificado: parser de RSS con feedparser
import feedparser
import hashlib
from datetime import datetime
def parse_feed(feed_url: str) -> list[dict]:
feed = feedparser.parse(feed_url)
articles = []
for entry in feed.entries:
content_hash = hashlib.sha256(
entry.get("link", "").encode()
).hexdigest()
articles.append({
"title": entry.get("title", ""),
"url": entry.get("link", ""),
"published": entry.get("published", ""),
"summary": entry.get("summary", ""),
"content_hash": content_hash,
"source": feed_url,
"ingested_at": datetime.utcnow().isoformat(),
})
return articlesPostgreSQL com a base de dades. Emmagatzema articles, metadades, estat de publicació i logs de processament. Uso camps JSONB per desar metadades variables (tags extrets per IA, puntuacions, entitats detectades). PostgreSQL aguanta això sense pestanyejar i m’evita haver de muntar un sistema separat per a dades semiestructurades.
BeautifulSoup i Playwright per a scraping. BeautifulSoup per a llocs amb HTML estàtic i Playwright per als que renderitzen amb JavaScript. La majoria de fonts de notícies segueixen servint contingut estàtic, així que BeautifulSoup cobreix el 80% dels casos. Playwright hi entra quan no hi ha alternativa.
APIs de LLM per al processament intel·ligent. Uso models a través d’API per classificar articles per categoria, generar resums curts i extreure entitats rellevants. No entreno models propis; això seria sobreenginyeria per a aquest cas d’ús.
Decisions tècniques que importen
Per què RSS + scraping (i no només un dels dos)
RSS és estable, ètic i fàcil de parsejar. Però no totes les fonts tenen RSS. I les que en tenen no sempre inclouen el contingut complet: moltes només exposen títol i un extracte.
El scraping complementa on RSS no arriba. Hi ha mitjans que no ofereixen feed, hi ha seccions específiques que no són al RSS general i hi ha dades estructurades (autor, categoria, data exacta) que el feed omet.
La combinació de RSS com a font primària i scraping com a fallback em dona cobertura àmplia sense dependre d’un sol mètode d’extracció.
Per què n8n i no Airflow
Airflow és una eina excel·lent per a pipelines de dades en producció. Però per a un projecte personal amb fluxos que modifico cada setmana, n8n té avantatges pràctics:
- La interfície visual redueix el temps d’iteració. Puc moure nodes, provar execucions parcials i veure dades intermèdies sense tocar codi.
- El self-hosting és trivial. Un contenidor Docker i llest.
- Per a fluxos d’orquestració (trigger → HTTP → processar → desar), n8n és més ràpid de muntar que escriure DAGs en Python.
On n8n flaqueja és en processament pesat. Per això la lògica complexa (parseig, deduplicació, IA) l’executo en scripts Python que n8n invoca com a serveis HTTP.
Per què no només APIs
Seria ideal que tots els mitjans exposessin APIs netes amb el seu contingut. Però la realitat és que la majoria no ho fan, i els que sí que ho fan solen tenir limitacions de rate, cost o accés.
RSS i scraping em donen independència. No depenc que un tercer mantingui una API ni que les seves condicions de servei canviïn d’un dia per l’altre. Òbviament, el scraping té els seus propis riscos (canvis d’estructura, bloquejos), però són riscos que puc gestionar tècnicament.
El flux de dades en detall
1. Ingesta
Cada font té un extractor dedicat. Els feeds RSS es processen amb feedparser. Els scrapers usen BeautifulSoup o Playwright segons el lloc. Cada extractor retorna un format normalitzat:
# Formato normalizado de artículo
{
"title": str,
"url": str,
"content": str, # texto limpio, sin HTML
"published_at": str, # ISO 8601
"source_name": str,
"source_type": str, # "rss" | "scraper" | "api"
"content_hash": str, # SHA-256 del contenido
"raw_metadata": dict, # datos originales sin procesar
}La deduplicació es fa en dos nivells: primer per URL exacta (el més obvi) i després per hash de contingut (per detectar el mateix article publicat a dos llocs diferents o amb URLs lleugerament diferents).
2. Processament amb IA
Un cop l’article està normalitzat i deduplicat, passa per un pipeline d’IA:
# Pipeline de procesamiento con LLM
def process_article(article: dict) -> dict:
prompt = f"""Analiza el siguiente artículo de noticias:
Título: {article['title']}
Contenido: {article['content'][:3000]}
Responde en JSON con:
- category: categoría principal (tech, política, economía, ciencia, etc.)
- summary: resumen de 2-3 frases
- entities: lista de entidades mencionadas (personas, empresas, tecnologías)
- relevance_score: puntuación de 1-10 según relevancia para una audiencia técnica
"""
response = call_llm(prompt)
enriched = article.copy()
enriched["ai_metadata"] = parse_json_response(response)
return enrichedAquest pas no és gratuït. Cada crida a l’API del LLM té un cost en tokens, i quan processes centenars d’articles al dia, la despesa s’acumula. Per això aplico un primer filtre abans de la IA: si l’article ja existeix a la base de dades o la seva font té una taxa de rellevància històricament baixa, no el processo.
3. Emmagatzematge
Tot va a PostgreSQL. La taula principal d’articles té columnes fixes per a les dades essencials i un camp JSONB per a les metadades d’IA:
CREATE TABLE articles (
id SERIAL PRIMARY KEY,
url TEXT UNIQUE NOT NULL,
title TEXT NOT NULL,
content TEXT,
published_at TIMESTAMP,
source_name TEXT NOT NULL,
source_type TEXT NOT NULL,
content_hash TEXT NOT NULL,
ai_metadata JSONB,
status TEXT DEFAULT 'pending', -- pending, approved, rejected, published
created_at TIMESTAMP DEFAULT NOW(),
published_to JSONB DEFAULT '[]'
);4. Validació editorial
Aquí és on el sistema deixa de ser automàtic. Els articles processats arriben amb estat pending a un panell intern on puc revisar-los, editar-los si cal i aprovar-los o descartar-los.
No és un panell sofisticat. És una interfície simple que mostra el títol, el resum generat per IA, la puntuació de rellevància i el contingut original. Des d’allà decideixo què es publica i què no.
Aquest pas sembla ineficient, però és el que marca la diferència entre un bot de spam i un canal amb criteri.
5. Distribució
Els articles aprovats es publiquen als canals configurats. Actualment Telegram i X, amb la web com a tercer canal en desenvolupament. Cada canal té el seu formatejador: Telegram usa Markdown amb emojis, X requereix versions curtes amb enllaç, la web mostra l’article complet.
n8n gestiona aquesta distribució. Quan un article passa a estat approved, un workflow es dispara, formata el contingut per a cada canal i el publica. Si la publicació falla (rate limit, error d’API), queda a la cua per a reintent.
Errors i limitacions actuals
No tot és bonic. Aquests són els problemes reals amb els quals convisc:
La deduplicació no és perfecta. Dos mitjans poden publicar la mateixa notícia amb textos prou diferents perquè el hash no coincideixi. Estic experimentant amb embeddings per detectar similitud semàntica, però afegeix complexitat i cost.
Els scrapers es trenquen. Un mitjà canvia el seu HTML i l’extractor deixa de funcionar. Tinc alertes configurades per detectar quan un scraper retorna menys resultats del que és habitual, però la resposta segueix sent manual: obrir el lloc, veure què ha canviat i actualitzar els selectors.
Els costos d’IA escalen malament. Processar 200 articles diaris amb un LLM no és car. Però si vull escalar a 2000 o gestionar articles més llargs, el cost es multiplica ràpid. Estic avaluant models més petits i fine-tunejats per a les tasques de classificació, que no necessiten el LLM més potent del mercat.
La validació editorial és un coll d’ampolla. Si no reviso els articles, no es publiquen. Això limita la freqüència de publicació. Estic treballant en un sistema de confiança per font: si una font té un historial consistent d’articles aprovats, els seus pròxims articles podrien publicar-se automàticament amb menys supervisió.
El panell intern és precari. Funciona, però no és còmode. No té filtres avançats, no permet agrupar articles per tema i la interfície és bàsicament una taula amb botons. És el típic que en un projecte personal sempre queda per a després.
Pròxims passos
Rolsfera no està acabat ni ho estarà aviat. Aquests són els fronts oberts:
Detecció de duplicats semàntics. Passar de comparació per hash a comparació per embeddings. La idea és que si dos articles parlen del mateix amb paraules diferents, el sistema els detecti com a duplicats i presenti només el millor.
Sistema de scoring per font. Assignar una puntuació de confiança a cada font basant-se en l’historial d’aprovacions i rebuigs. Això permetria automatitzar la publicació de fonts d’alta confiança.
Interfície web pública. Treure Rolsfera del meu panell intern i convertir-lo en un producte que altres puguin usar. Això implica autenticació, personalització de fonts i una capa de presentació decent.
Diversificar els canals de distribució. Newsletter, RSS propi (irònic, ho sé) i potser integració amb lectors de feeds.
Optimitzar costos d’IA. Avaluar models més petits per a classificació i reservar els LLMs grans només per a resums i tasques que realment ho necessitin.
Reflexió final
Rolsfera no és un projecte revolucionari. És un agregador de notícies amb scraping i IA, un concepte que existeix des de fa anys. El que el fa interessant per a mi és que és un laboratori real on provo idees d’arquitectura, automatització i processament de dades que després aplico en altres contextos.
Si alguna cosa he après construint-lo és que la part difícil no és muntar el pipeline. És mantenir-lo funcionant quan les fonts canvien, els costos s’acumulen i la vida real et deixa poc temps per revisar articles. L’arquitectura ha d’absorbir aquesta realitat, no ignorar-la.
I això, crec, és el que diferencia un side project que sobreviu d’un que mor al tercer commit.


