Verificación de Pagos Inteligente
Universidad Nacional de Colombia · 2026 - Actualmente
Un contratista de la Universidad Nacional debe demostrar, cada mes, que sus aportes a seguridad social están al día antes de que le paguen. Esta aplicación toma ese trámite completo — leer el contrato, el certificado ARL y la planilla PILA, contrastar las cifras con la normativa colombiana y llenar los formatos institucionales — y lo convierte en un asistente de cuatro pasos para la Dirección de Investigación y Extensión de la sede Manizales.
Arquitectura y Stack Tecnológico
Arquitectura Central
- Framework: Next.js 16 (App Router), TypeScript, desplegado en Vercel
- Extracción con IA: Vercel AI SDK sobre una cadena de modelos Mistral + OpenAI con fallback automático (
src/lib/ai/client.ts) - Lectura de documentos:
unpdf/mupdfpara PDFs digitales, OCR de Mistral para escaneados y pantallazos - Reglas de negocio: motor de cálculo puro para el formato 069, parametrizado por vigencia (
src/lib/formato069/) - Validación: esquemas Zod por tipo de documento (contrato, ARL, planilla, informe)
- Generación de PDF:
@pdfmellenando los formatos oficiales, unidos con sus anexos - Estado: store de Zustand a lo largo de los pasos del asistente
- UI: shadcn/ui + Tailwind CSS 4
- Analítica: PostHog detrás de una whitelist tipada de eventos
Arquitectura en Capas
El navegador nunca habla directo con un modelo: cada extracción pasa por un route handler que devuelve NDJSON en streaming, así el asistente va pintando los campos a medida que se reconocen en vez de esperar al documento completo.
Flujo de una Petición
Características Principales
Características de un Vistazo
Carga de varios documentos
Contrato, certificado ARL, planilla PILA pagada y — cuando el contrato lo exige — el informe de actividades, todos de una vez. Cada archivo se perfila y valida antes de la extracción (src/lib/pdf/document-profiles.ts, document-validator.ts), de modo que un documento equivocado se detecta en la puerta y no a mitad del flujo.
Extracción con nivel de confianza por campo
El modelo devuelve cada campo marcado con su nivel de confianza. El paso 2 muestra esas marcas, así el esfuerzo de revisión se concentra en lo realmente dudoso en vez de releerlo todo. El usuario corrige en línea y los valores corregidos alimentan el resto del flujo.
Validación contra la normativa
Aportes, vigencia y cobertura de la ARL, plazos PILA, porcentajes del informe y la certificación tributaria los revisan validadores independientes orquestados en src/lib/validations/index.ts. Cada hallazgo cita la norma exacta de la que sale — y solo normas cuyo texto se verificó directamente.
Motor de cálculo del formato 069
Un motor puro, sin efectos secundarios, calcula la base de aportes y las deducciones. Los parámetros de la vigencia viven en archivos propios (params/2026.ts, params/2027.ts), así que pasar la app a un año nuevo es un cambio de parámetros, no una reescritura.
Salida lista para firma
Los formatos oficiales U.FT.12.010.053 y U.FT.12.010.069 se llenan y se unen con sus anexos en un único PDF descargable.
Destacados Técnicos
No se cita lo que no se ha leído
src/lib/constants/fuentes.ts solo lleva normas cuyo texto se verificó de primera mano, y la regla se extiende a las frases entrecomilladas dentro de los mensajes de validación. Una cita atribuida a la Circular GNFA 019/2018 resultó no existir y hubo que revertirla; se repitió con una frase del Formato 053. Cuando un documento no se puede abrir, la app lo dice en vez de reconstruirlo.
Analítica que no puede filtrar a una persona
src/lib/analytics.ts admite solo enums, conteos, booleanos y claves de campo — nunca valores, nombres, cédulas, montos ni contenido de documentos. El tipo EventMap es la whitelist y TypeScript la impone en compilación. Los identificadores de regla tampoco se renombran: identifican la situación, no la redacción, así la serie histórica en PostHog sigue siendo comparable.
Manda el Excel oficial
Cuando la investigación normativa y el .xlsx oficial se contradicen, gana el Excel: la app debe reproducir el formato que la Universidad realmente recibe, no el que la norma sugiere.
Nunca sobrescribir en silencio una declaración
El Formato 053 es una declaración firmada. Una coerción automática del tipo de pago a "Único" cambiaba por detrás lo que el contratista había marcado; se eliminó y se sustituyó por un aviso. Cuando la app detecta una inconsistencia, la señala y deja decidir a la persona.
Fechas que muchas veces no están
Cerca de la cuarta parte de los contratos expresa el plazo solo en días ("doscientos sesenta y ocho (268) días calendario"), así que startDate/endDate llegan null y solo existe durationDays. La app infiere fechas desde el certificado ARL únicamente cuando el emparejamiento es inequívoco; si no, el usuario teclea la fecha de inicio y la de fin se deriva con el mismo utilitario compartido, sin pisar nunca una fecha de fin ya puesta.
Un corpus de casos reales como arnés de pruebas
docs/Casos/ guarda PDFs reales emparejados con expected.json — operadores, aseguradoras de ARL, formas de contrato y los casos incómodos: escaneados, pantallazos, páginas rotadas, ARL vencida, aportes incompletos, varias planillas. Más de una heurística "obvia" ha fallado contra él, y por eso cada cambio de regla o de extractor se vuelve a pasar por el corpus antes de salir. "Funciona con mi documento" no es evidencia.
Estructura del Proyecto
src/ ├── app/ │ ├── api/extract/ # extracción con IA, streaming NDJSON │ ├── api/extract-text/ # capa de texto + fallback OCR │ ├── api/generate-pdf/ # llena y une los formatos oficiales │ └── verify/ # el asistente de cuatro pasos ├── components/ │ ├── upload/ # dropzone + formulario manual │ └── wizard/ # step-1 … step-4, editores de extracción ├── lib/ │ ├── ai/client.ts # cadena de modelos + fallback │ ├── extraction/ # anclas, preprocesado, inferencia de nombre │ ├── formato069/ # motor de cálculo puro + parámetros por vigencia │ ├── pdf/ # perfiles, validador, OCR, llenado de formatos │ ├── validations/ # aportes, fechas, plazos, informe │ ├── schemas/ # esquema Zod por tipo de documento │ ├── constants/fuentes.ts # catálogo de normas verificadas │ └── analytics.ts # whitelist tipada de eventos docs/ ├── LOGICA-NEGOCIO.md # fuente única de verdad de las reglas └── Casos/ # corpus de PDFs reales con expected.json
Impacto y Escalabilidad
- Reemplaza un trámite completamente manual: leer cada documento a mano, cruzar cifras y digitar los formatos.
- El tiempo de revisión se concentra en los campos de baja confianza en vez de en todos.
- Pasar a una vigencia nueva es un solo archivo de parámetros.
- El corpus de casos hace que cada cambio de regla sea verificable contra documentos reales antes de salir.
- El uso se mide en PostHog sin guardar un solo valor personal.
Notas
Construido con Next.js 16, el Vercel AI SDK sobre Mistral y OpenAI, @pdfme, Zod y shadcn/ui. El repositorio es privado — pertenece al Centro de Prototipado de la Universidad Nacional de Colombia.