Correspondencia Jurídica Inteligente

Universidad Nacional de Colombia · 2026 - Actualmente

Next.jsSupabaseAI SDKGmail API

La Vicerrectoría de Sede firma resoluciones, viáticos y comisiones que llegan por correo desde todas las dependencias del campus. Esta aplicación convierte ese buzón en un flujo con trazabilidad: un agente ingiere los correos, una IA los resume y clasifica, la secretaria revisa y asigna, el Vicerrector decide, y el documento aprobado vuelve firmado, archivado y enviado a quien lo solicitó.

Arquitectura y Stack Tecnológico

Arquitectura Central

  • Framework: Next.js 16 (App Router), React 19, TypeScript
  • Base de datos y autenticación: Supabase (@supabase/ssr) con row-level security en todas las tablas y almacenamiento privado de documentos
  • IA: Vercel AI SDK con @ai-sdk/mistral, modelo mistral-medium-2508
  • Documentos: pdf-parse para el texto con fallback a OCR de Mistral, pdf-lib para estampar la firma, pdfjs-dist para renderizar la página y ubicarla
  • Google: googleapis para la API de Gmail (ingesta) y la de Drive (archivo), cada una con sus propias credenciales acotadas
  • UI: shadcn/ui (base-nova) + Tailwind CSS 4, siempre en español a través de un mapa de etiquetas
  • Pruebas: Vitest sobre la lógica de firma, rollback, actividad y prompts

Arquitectura en Capas

Flujo de una Petición

Características Principales

Características de un Vistazo

Ingesta automática desde Gmail

Los mensajes se traen directamente del buzón de la Vicerrectoría — sin filtro de remitente, así nadie tiene que reenviar nada a mano — y se toma cualquier adjunto PDF o Word. Los archivos Word se convierten y los escaneados caen al OCR de Mistral.

Resumen ejecutivo, temática y acción sugerida

Para cada radicado la IA escribe un resumen ejecutivo, clasifica la temática en una de seis categorías reales (resolucion, viaticos_comisiones, presupuesto, permiso, personal, otro) y sugiere una acción: aprobar, informar o remitir. Ante la duda se abstiene a otro — una etiqueta equivocada con seguridad cuesta más que un honesto "sin clasificar".

Checklist de vistos buenos

Una heurística detecta qué vistos buenos trae el documento (Jurídica, Dirección Administrativa, Presupuesto), leyendo tanto el correo como los sellos "Vo.Bo." dentro del texto del PDF. La falta de un visto bueno se muestra como observación, nunca como bloqueo: decide la secretaria.

Bandeja por rol

Una sola bandeja, dos vistas. El Vicerrector decide (aprobar, informar, remitir o negar con motivo obligatorio); la secretaria revisa, ajusta vistos buenos y observaciones, asigna, firma, despacha y puede reabrir un radicado ya procesado para corregirlo, conservando la nota del Vice.

Firma posicionable

La secretaria carga un PNG de la firma, la arrastra y redimensiona sobre la página del PDF renderizada (signature-placer.tsx), y se estampa en el servidor con pdf-lib. El archivo firmado se archiva en Drive, el original se borra del bucket y el documento se envía por correo al solicitante detectado del CC.

Destacados Técnicos

El clasificador se midió, no se supuso

El prompt de acción se reescribió a partir de las correcciones reales de la secretaria y se evaluó contra un corpus etiquetado: el acierto pasó de ~82% a ~88%, sin regresión en aprobar. remitir sigue siendo la clase difícil — decidir a qué dependencia va un documento depende de un conocimiento de enrutamiento que el texto simplemente no trae.

La firma nunca se guarda

Se carga en el navegador, vive en memoria y se envía solo en el momento de firmar. No hay archivo de firma en el servidor ni columna de firma en la base de datos — nada que filtrar si alguno llegara a comprometerse.

El acceso está cerrado por construcción

El login es Google OAuth restringido al dominio de la Universidad, exigido tanto en la petición al proveedor como revalidado en el servidor después — una comprobación de dominio solo en el cliente no es una comprobación. Y entrar no basta: la cuenta tiene que estar aprovisionada de antemano, y sin perfil no hay acceso a nada. Row-level security activo en todas las tablas, y cada server action verifica el rol de quien llama antes de ejecutar una operación privilegiada.

Un corpus de correos que sigue mejorando el modelo

Un corpus etiquetado empareja la salida del propio clasificador con la corrección que hizo una persona. Eso es lo que permite medir un cambio de prompt en vez de adivinarlo — y lo que convirtió "el prompt nuevo se siente mejor" en 82% → 88%.

Código en inglés, dominio en español

Tablas, columnas e identificadores van en inglés; los valores de enum son los términos propios del dominio en español (pendiente, por_firmar, firmado, informado, remitido, resuelto, negado), y la UI siempre en español vía src/lib/labels.ts. Nadie hardcodea una etiqueta y nadie tiene que traducir un estado mentalmente.

Estructura del Proyecto

src/
├── app/
│   ├── actions/requests/     # firma, decisiones, anexos, consultas, metadatos
│   ├── api/                  # ingesta programada, autorización de Google, entrega del documento
│   ├── bandeja/              # la bandeja: listado, diálogos, ubicador de firma
│   └── manual/               # manual embebido por rol
├── lib/                      # bitácora, estado de lectura, etiquetas, nombres de documento
├── utils/
│   ├── ai.ts, ai-prompts.ts  # runMistral + prompts y parsers puros
│   ├── classify.ts, summary.ts, date-audit.ts
│   └── gmail-ingest.ts       # ingesta + enriquecimiento con IA
└── types/database.ts         # tipos generados de Supabase

Impacto y Escalabilidad

  • Radicación, revisión, redacción, firma y envío viven en un solo flujo en vez de repartidos entre buzones y carpetas compartidas.
  • request_events mantiene la trazabilidad de quién hizo qué y cuándo — incluidas las negaciones, cuyo motivo queda interno.
  • La clasificación va en ~88% de acierto y es medible contra un corpus etiquetado, así que el próximo cambio de prompt se puede demostrar en vez de discutir.
  • Pendientes conocidos: numeración de resoluciones, plantilla del correo de envío, plazos de derechos de petición, el Drive institucional definitivo y la firma certificada con Adobe (aplazada).

Notas

Construido con Next.js 16, Supabase, el Vercel AI SDK sobre Mistral, las APIs de Gmail y Drive, pdf-lib y shadcn/ui. El repositorio es privado — pertenece al Centro de Prototipado de la Universidad Nacional de Colombia.