Extracción de facturas electrónicas
Una app web que se conecta a un buzón por IMAP, trae los adjuntos comprimidos de facturas electrónicas colombianas, los descomprime de forma segura y extrae el CUFE y todo el detalle de la factura del XML UBL 2.1 de la DIAN, separado por empresa y exportable a Excel.
Camino de una petición en producción
- asistente Reactbuzón y rango de fechas
- FastAPIJWT, tarea en segundo plano
- IMAP sobre SSLbúsqueda por fecha, lotes de 10
- capa de archivoscontroles de seguridad, formatos intercambiables
- parseo UBL 2.1XPath ordenado, sin modelo
- PostgreSQLseparado por empresa
- exportación a Exceltres hojas
Qué corre dónde
API
FastAPI
Autenticación, procesamiento de buzones, resultados y exportaciones. Los procesos largos corren como tareas en segundo plano para que la petición responda de inmediato.
Capa de archivos
Handlers intercambiables
ZIP y TAR por defecto, con handlers de 7Z y RAR detrás de feature flags, todos pasando por los mismos controles de seguridad.
Extracción
lxml + XPath
Primero el CUFE y luego el detalle de la factura: emisor, totales, impuestos, ítems, descuentos y cargos.
App web
React + TypeScript
Un asistente paso a paso para procesar un buzón, un tablero con resultados y un área de administración para usuarios y empresas.
Decisiones de arquitectura
- De cuatro servicios a uno
- Empezó como cuatro microservicios hablando por HTTP. Los uní en un solo backend: llamadas directas en vez de saltos de red, un contenedor para desplegar y un solo lugar para probar.
- Etapas guiadas por estado
- Cada etapa toma el trabajo que tiene pendiente (descargado, extraído, CUFE encontrado, detalle leído), así que un correo o archivo dañado nunca detiene el lote.
- Determinista antes que generativo
- Construí un respaldo con LLM con salida validada por esquema y registro de costos, y luego lo saqué del camino en vivo: el XPath sobre la estructura UBL resultó más confiable y no cuesta nada por factura.
- Archivos temporales
- Los adjuntos viven en almacenamiento temporal solo mientras dura el proceso y se borran después de guardar en la base de datos.
- Las credenciales del buzón nunca se guardan
- Se envían para un proceso, se usan en una sesión IMAP y se descartan.
- Camino a clean architecture
- Capas de dominio, aplicación e infraestructura con interfaces de repositorio y un contenedor de inyección de dependencias, migradas módulo por módulo.
Leer facturas electrónicas colombianas
- UBL 2.1 y namespaces de la DIAN
- El parser conoce los componentes comunes de UBL y las extensiones de la DIAN, en vez de adivinar sobre el texto.
- CUFE, con respaldos
- Primero XPath ordenado y con nivel de confianza; luego la clave del documento dentro de los datos del QR; la búsqueda en texto solo como último recurso.
- Documentos envueltos
- Maneja el sobre de documento adjunto que trae la factura real por dentro.
- Detalle completo
- Emisor, valores e impuestos, ítems, y descuentos y cargos, enlazados al correo del que vinieron.
Descomprimir archivos no confiables
- Límites de tamaño
- Un tope para el tamaño del archivo y para el tamaño total descomprimido.
- Control de zip bombs
- Los archivos con una relación de compresión extrema se rechazan antes de extraerlos.
- Límites de archivos
- Un máximo de archivos extraídos y una lista de extensiones permitidas.
- Path traversal
- Se rechazan las rutas relativas y absolutas que intentan salir, y cada destino se resuelve para confirmar que queda dentro de la carpeta de extracción.
Usuarios, empresas y despliegue
- Cuentas y roles
- Sesiones JWT, contraseñas con bcrypt y roles separados de usuario y administrador.
- Datos por empresa
- Los resultados y exportaciones se filtran por la empresa del usuario que inició sesión.
- Contenedores
- Una imagen Docker para la API y un build de la app servido con nginx, desplegados en Render, con una variante serverless que escala a cero.
- Pruebas
- 55 pruebas automatizadas sobre la extracción del XML, el procesamiento de buzones contra un servidor IMAP simulado, los repositorios y los servicios.