Cómo construí Boletín Claro: arquitectura de un SaaS sobre boletines oficiales
Cada día se publican cientos de entradas en los boletines oficiales españoles: el BOE, el BDNS, los boletines autonómicos. Subvenciones, licitaciones, normativa. La mayoría de pequeñas empresas se entera tarde o nunca. Construí Boletín Claro para resolver exactamente eso: un sistema que lee los boletines por ti, extrae lo relevante y te lo envía resumido cada mañana.
En este artículo voy a desgranar la arquitectura técnica del proyecto, las decisiones de stack y los problemas más interesantes que he tenido que resolver.
El problema
Los boletines oficiales son la fuente primaria de información sobre ayudas públicas, contratos y regulación en España. Pero están diseñados para cumplir requisitos legales, no para ser útiles. Los PDFs del BOE no tienen estructura semántica. El BDNS expone una API REST pero con paginación errática. Los boletines autonómicos van desde XML razonablemente limpio hasta HTML de los años 2000.
El usuario objetivo es una pyme o un autónomo que necesita saber si hay una subvención relevante para su negocio, pero que no puede permitirse dedicar una hora al día a rastrear 20 fuentes distintas. El producto hace tres cosas: recopilar, interpretar y entregar.
Arquitectura general
El sistema se compone de cinco servicios independientes, cada uno desplegado en Cloud Run:
- Reader (Python + FastAPI): se conecta a las fuentes oficiales, descarga los boletines del día y los convierte a markdown estructurado. Un servicio por fuente sería excesivo, así que internamente hay un cliente HTTP por boletín con una interfaz común.
- Interpreter (Python + FastAPI): recibe las entradas del reader, aplica filtros de relevancia y genera resúmenes con LLMs. También gestiona el envío de emails.
- Backend (Go + Gin): API REST para el frontend. Gestiona usuarios, workspaces, alertas y planes. Firebase Auth para autenticación, Firestore como base de datos.
- Location (Go + Gin): sidecar geográfico. Resuelve municipios, provincias y comunidades autónomas a partir de códigos INE. Necesario para filtrar boletines por territorio.
- Tools (Go + Gin): herramientas públicas de búsqueda semántica sobre boletines. Es el servicio que alimenta los buscadores de boletines.
El frontend es React 19 con TypeScript, Vite y TailwindCSS v4. Toda la infraestructura está definida con Terraform.
Por qué este stack
Go para la API y los servicios auxiliares
Go es una elección natural para servicios que necesitan arrancar rápido y consumir poca memoria. En Cloud Run pagas por tiempo de ejecución, así que un cold start de 200ms frente a 2 segundos marca la diferencia. El backend maneja autenticación, CRUD y lógica de negocio: exactamente el tipo de código donde Go brilla por su simplicidad.
Python para el procesamiento de datos
El reader y el interpreter necesitan parsear HTML, XML, PDFs, hacer llamadas a APIs de IA y manipular texto. Python es imbatible para eso. beautifulsoup4 para HTML, lxml para XML, pdfplumber para extraer texto de PDFs. FastAPI como framework HTTP porque el tipado con Pydantic reduce errores en los contratos entre servicios.
Firebase y Firestore
No necesito joins complejos ni transacciones distribuidas. Lo que necesito es autenticación resuelta (magic links + Google OAuth), una base de datos que escale sin gestión y un free tier generoso para arrancar. Firestore cumple todo eso. El modelo de datos es jerárquico: workspaces/{id}/alerts/{id}, que es exactamente cómo funciona Firestore con subcollections.
El pipeline diario
Cada mañana, un Cloud Scheduler dispara el reader. El flujo es:
- El reader recorre las fuentes configuradas y descarga los boletines del día.
- Cada boletín se parsea a una estructura uniforme: título, texto, metadata, fuente.
- Las entradas se almacenan en Firestore y se generan embeddings para búsqueda semántica.
- El interpreter recibe las entradas nuevas, las filtra contra las alertas de cada usuario y genera resúmenes con el LLM.
- Los resúmenes se envían por email a los usuarios suscritos.
Todo es idempotente. Si el reader se ejecuta dos veces para la misma fecha, no duplica entradas. Si el interpreter procesa una alerta que ya procesó, detecta el duplicado y no envía email.
Desafíos técnicos
Parsear PDFs del gobierno
Los PDFs del BOE son el reto más interesante. No son PDFs con texto seleccionable de forma consistente. Algunos tienen capas de texto, otros son imágenes escaneadas. Hay tablas que se rompen entre páginas. He probado pdfplumber, pymupdf y pdfminer en distintas combinaciones. La solución final usa pdfplumber para la extracción base y heurísticas propias para reconstruir la estructura de secciones.
Costes de IA
Pasar 300 entradas de boletines por un LLM cada día no es barato. La clave es filtrar antes de resumir. El interpreter primero aplica filtros de relevancia por palabras clave y embeddings, y solo envía al LLM las entradas que superan un umbral. Esto reduce el volumen de tokens un 85-95% frente a resumirlo todo.
Consistencia entre servicios
Con cinco servicios independientes, la comunicación es clave. Uso HTTP síncrono entre servicios (no eventos), lo que simplifica el debugging. Cada servicio tiene su health check y Cloud Run gestiona el escalado. No hay orquestador central: el Cloud Scheduler dispara el reader, el reader llama al interpreter cuando termina, y el interpreter es autónomo para el envío.
Estado actual y futuro
Boletín Claro procesa actualmente el BOE, BDNS y varios boletines autonómicos. El sistema es estable: funciona desatendido cada día y el ratio de fallos es inferior al 1%. Las alertas se pueden configurar con lenguaje natural ("subvenciones para digitalización de pymes en Madrid") y el sistema se encarga de traducirlo a filtros técnicos.
Los próximos pasos van por mejorar la cobertura de boletines autonómicos y añadir canales de entrega (Telegram, WhatsApp). También estoy trabajando en herramientas públicas gratuitas de búsqueda sobre los datos recopilados, que cualquiera pueda usar sin necesidad de cuenta.
Si estás construyendo algo similar o tienes dudas sobre la arquitectura, me puedes encontrar en LinkedIn.