Saltar al contenido principal
Open Source · IA

docu-ai-flow

Servicio .NET 10 que vigila una carpeta, extrae los datos de las facturas PDF, las archiva y envía el trimestre al asesor. Dos ideas lo sostienen: la extracción vive detrás de un único port —hoy plantillas locales, ayer Google Document AI— y ninguna factura se archiva sola hasta que su proveedor se lo ha ganado. Se ejecuta con dos comandos y sin una sola credencial.

El problema

Gestionar facturas de proveedores es trabajo manual repetitivo: descargar PDFs, abrirlos uno a uno, copiar datos a una hoja de cálculo, enviarlos al asesor cada trimestre. Un error en cualquier paso significa declaraciones incorrectas. Pero automatizarlo del todo tiene su propia trampa: ninguna extracción acierta el 100% de las veces, y una cifra mal leída que nadie mira acaba en una declaración.

La solución

  • Watcher de carpeta

    Detecta PDFs en ./data/inbox/ en tiempo real. Un watcher de filesystem más polling de seguridad garantizan que ninguna factura se pierda. Detecta duplicados por hash y también por clave natural (número + CIF), que es lo que caza una factura reenviada con bytes distintos antes de declarar el mismo IVA dos veces.

  • Extracción intercambiable

    Un único port, IInvoiceDataExtractor, con dos adaptadores vivos: plantillas locales sobre PdfPig (el que va por defecto: sin red, sin credenciales, 0 € por factura) y Google Document AI. Cuál está activo es un valor de configuración, no un cambio de código.

  • OCR para escaneos

    Un escaneo no tiene capa de texto, así que no hay nada que leer. Con el fallback activado, poppler rasteriza la página y Tesseract la lee; el texto recuperado sigue el mismo camino de plantillas. Desactivado, un Null Object devuelve cadena vacía y ninguna rama del extractor necesita preguntar si el OCR existe.

  • Revisión con el PDF al lado

    Las facturas que no se archivan solas esperan en una cola. La pantalla de revisión pone el PDF a la izquierda y los campos extraídos a la derecha, cada uno con la confianza con la que se capturó. Lo que el extractor no supo leer se convierte en un formulario en blanco, con su propia validación de que base + IVA = total.

  • Exportación a Excel

    ClosedXML genera un Excel trimestral con tipos nativos — fechas y números reales para ordenar, filtrar y sumar sin conversiones. El maestro acumulativo se regenera con cada factura confirmada.

  • Envío al asesor

    Resend empaqueta los PDFs del trimestre en un ZIP y los envía al asesor fiscal. Si el ZIP supera el límite de 40 MB de Resend, se divide automáticamente por mes y se envían varios correos.

La pantalla de revisión: el PDF a la izquierda, los campos extraídos a la derecha con la confianza de cada uno, y cuánto le falta al proveedor para archivarse solo.

La pantalla de revisión: el PDF a la izquierda, los campos extraídos a la derecha con la confianza de cada uno, y cuánto le falta al proveedor para archivarse solo.

La pantalla de revisión: el PDF a la izquierda, los campos extraídos a la derecha con la confianza de cada uno, y cuánto le falta al proveedor para archivarse solo.

Pruébalo

No hace falta clonar nada ni tener .NET instalado. La imagen se publica en GHCR desde CI, para amd64 y arm64, y arranca con el extractor local: sin cuentas, sin claves.

  1. 1 Genera ocho facturas ficticias en la bandeja de entrada
    docker run --rm -v "$PWD/data:/app/data" \
      ghcr.io/aitorevi/docu-ai-flow:latest make-samples /app/data/inbox
  2. 2 Arranca el watcher y el panel
    docker run --rm -p 8080:8080 -v "$PWD/data:/app/data" \
      ghcr.io/aitorevi/docu-ai-flow:latest

Abre localhost:8080. Tres de esas facturas son del mismo proveedor: confírmalas sin cambiar nada y verás a Suministros Aurora pasar de «En revisión» a «Automático» — a partir de ahí sus facturas se archivan solas. Esa es la idea que sostiene el proyecto, y se ve en un minuto.

El panel: lo que hay por revisar, lo ya archivado, y una barra de confianza por proveedor — Suministros Aurora ya en automático.

El panel: lo que hay por revisar, lo ya archivado, y una barra de confianza por proveedor — Suministros Aurora ya en automático.

El panel: lo que hay por revisar, lo ya archivado, y una barra de confianza por proveedor — Suministros Aurora ya en automático.

Stack técnico

Backend

  • .NET 10
  • C#
  • Hexagonal
  • Result/Error
  • SQLite
  • PdfPig
  • Google Document AI
  • Tesseract
  • Resend
  • Polly

Frontend y despliegue

  • Astro 6
  • TypeScript
  • Docker
  • GHCR
  • GitHub Actions

Tests

  • xUnit
  • NSubstitute
  • WireMock.Net
  • NetArchTest
  • WebApplicationFactory

Decisiones técnicas

  • Arquitectura hexagonal

    El extractor, SQLite, el archivador y Resend son adaptadores intercambiables detrás de interfaces (ports). Los use cases del Application no conocen ningún detalle de implementación. Un test de arquitectura con NetArchTest verifica que las fronteras nunca se crucen en cada build.

  • El hexágono, demostrado

    El proyecto empezó con LlamaParse, se pasó a Google Document AI cuando su precisión se quedó corta, y acabó en un extractor local por plantillas que gana a los dos en las facturas que de verdad ve. En los tres cambios el dominio, los use cases y los tests de pipeline no se tocaron: dependen del port, no del proveedor. Ese es todo el retorno del hexágono, y por eso hoy el que va por defecto es el gratis.

  • Confianza que se gana

    La pregunta interesante no es si un humano revisa, sino qué facturas se ganan el derecho a saltarse la revisión — y eso se decide por proveedor, por historial. Tras N confirmaciones seguidas en las que nadie corrigió nada, ese proveedor pasa a archivarse solo. Una sola corrección reinicia el contador y le retira la confianza. La autonomía se gana y se puede perder.

  • Result/Error para errores de negocio

    Un error de extracción (confianza baja, total incoherente, número ausente) es un caso de negocio esperado, no una excepción. Result<TValue, TError> lo expresa como un valor de retorno. Las excepciones quedan para lo transitorio — API caída, disco lleno — que Polly reintenta automáticamente.

  • Ejecutable sin credenciales

    Un proyecto de portfolio que solo se puede leer vale la mitad. La imagen se publica en GHCR desde CI, trae poppler y Tesseract dentro, y arranca con el extractor local: dos comandos de Docker, sin cuentas ni claves, y ocho facturas ficticias que recorren todos los caminos — incluida una que ningún proveedor conoce y un escaneo sin texto.

  • Desarrollado con agentes de Claude Code

    Cada feature siguió el mismo ciclo: el orquestador exploró y debatió el enfoque, el planner diseñó la arquitectura, el coder implementó en TDD y el reviewer auditó contra el plan aprobado. El resultado: código consistente y un historial de commits que cuenta la historia de cada decisión.

Construido con Claude Code

El proyecto es también un experimento sobre cómo organizar el desarrollo asistido por IA. Los agentes y skills están en .claude/ y forman parte del repo público.

  • Orquestador

    Coordina el flujo completo: explora, debate, planifica, implementa y revisa. Ninguna fase comienza sin acuerdo explícito. El plan vive en workflow/ y viaja por plans/ → in-progress/ → reviewing/ → done/.

  • Agentes especializados

    planner-backend diseña la arquitectura y los contratos; coder-backend implementa en TDD estricto; reviewer audita contra el plan aprobado. Cada agente tiene su propio system prompt en .claude/agents/.

  • Skills reutilizables

    Skills en Markdown cargadas al inicio de cada sesión: commit.md define el formato de commits, tdd.md codifica el ciclo Red-Green-Refactor y orchestrate.md el flujo completo de orquestación.

  • TDD asistido por IA

    Cada feature empieza con un test en rojo. 262 tests en tres capas: Domain (puro), Application (use cases con dobles NSubstitute) e Integration — SQLite y ficheros reales, la API entera levantada en proceso con WebApplicationFactory, y un test de pipeline que lleva a un proveedor desde la primera revisión hasta archivarse solo.

¿Te interesa el workflow de IA?

El repo es público y se ejecuta sin credenciales. Los agentes, skills y el flujo de orquestación están en .claude/ junto al código fuente. Úsalos como plantilla para tus propios proyectos.