Siete agentes IA cubren el ciclo de vida del contrato: generación con plantillas Jinja2 + WeasyPrint, firma electrónica vía Mifiel con multi-firmante y QR móvil, vigilancia diaria de vencimientos, renovación automática, y OCR Vision para contratos legacy. Retention SAT 7 años cumplida automáticamente.
Supervisor Sonnet con LangGraph. Generador + validadores para el frontend, comunicador para outbound, vigilante + renovador como cron, lector como OCR legacy.
recursion_limit=25. Regla: toda comunicación outbound pasa por Comunicador M3.SandboxedEnvironment (no escape posible) + variables proveedor + items. Genera PDF con WeasyPrint. Sube a Supabase Storage y crea row contratos en estado borrador.enviado_firma → firmado_parcial → firmado_completo.simulation_mode para testing sin consumir Mifiel credits.borrador para revisión humana antes de mandar firma.origen='legacy_importado' + confianza por campo.De creación a firma completa, con Mifiel + QR móvil multi-firmante.
aprobado en M1), elige plantilla, llena variables. Click Generar.validado. Si falla, lista faltantes y bloquea.simulation_mode=true por default para testing. Crea documento en Mifiel, obtiene URL firma + token QR para cada firmante proveedor./firma/<token> pública, optimizada para celular.firmado_parcial. Comunicador notifica "firma parcial recibida".firmado_completo. Mifiel genera PDF final firmado. Se guarda URL definitiva en contratos.pdf_firmado_url.fecha_vencimiento. A los 30d, 15d, 7d antes → nudge. Al vencimiento → disparo Renovador.borrador. Usuario revisa y dispara nuevo ciclo de firma.8 estados. legacy_importado es terminal para contratos ya firmados fuera.
borrador ─→ enviado_firma ─→ firmado_parcial ─→ firmado_completo ─→ vencido ─→ renovado
│ │ │ │
└──→ cancelado └──→ cancelado (legacy importado desde PDF — entra directo a firmado_completo)
4 tablas per-tenant específicas de M3. Cross-ref con proveedores de M1.
| Tabla | Propósito | Campos clave |
|---|---|---|
contratos | Contrato raíz | proveedor_id, plantilla_id, estado, pdf_borrador_url, pdf_firmado_url, fecha_inicio, fecha_vencimiento, monto, origen (manual/legacy) |
contratos_firmantes | Multi-firmante | contrato_id, tipo (proveedor/cliente), nombre, email, mifiel_doc_id, firmado_en |
contratos_eventos | Timeline + auditoría | tipo (creado/enviado/firmado/vencido/renovado), meta JSONB, usuario |
plantillas_contrato | Jinja2 templates | nombre, contenido, variables_requeridas, activa |
Requisito: el proveedor debe estar aprobado. Validación al crear contrato.
API oficial Mifiel. Crea documento, obtiene URLs de firma + QR tokens. Webhook inbound en firma. Simulation mode default.
Todas las plantillas renderizan en sandbox: no __class__, no accesos a globals. Seguro contra injection en variables del usuario.
Render con timeout 10s vía ThreadPoolExecutor (thread-safe bajo gunicorn). Branding per-tenant aplicado.
Bucket contratos con subpaths por tenant. Signed URLs con TTL configurable. Backup automático.
Endpoint /firma/<token> pública (sin auth), token 1-use, TTL 7 días. Página optimizada móvil.
M4 bloquea crear OC si no hay contrato firmado_completo. Cross-check automático del validador M4.
Cron mensual marca contratos elegibles para archivado. Cumple obligación fiscal automáticamente.
/api/contratos/*POST /api/contratos # crear (Generador + Validador_completitud) GET /api/contratos # listado + filtros (estado, proveedor) GET /api/contratos/<id> # detalle + firmantes + eventos PATCH /api/contratos/<id> # update borrador POST /api/contratos/<id>/enviar # dispara Comunicador + Mifiel POST /api/contratos/<id>/cancelar # solo si no firmado POST /api/contratos/<id>/renovar # fuerza Renovador GET /api/contratos/<id>/pdf # signed URL del PDF actual POST /api/contratos/legacy/importar # upload PDF legacy → Lector OCR POST /webhook/mifiel # Mifiel firma callback (HMAC verify) GET /firma/<token> # página pública firma móvil (sin auth) POST /firma/<token>/confirmar # confirma firma vía QR móvil GET /api/plantillas # CRUD plantillas POST /api/plantillas PATCH /api/plantillas/<id> DELETE /api/plantillas/<id> GET /api/contratos/vencimientos # upcoming renewals (vigilante UI) GET /api/contratos/retention # contratos archivados SAT 7a
Bloqueo de escape: {{ config.__class__ }} no funciona. Variables de usuario no pueden acceder internals de Python.
Reenvíos del mismo event_id no duplican firmas ni transiciones. HMAC verify. Replay attacks bloqueados.
Firma móvil pública pero el token se invalida tras firmar. TTL 7 días desde envío. Sin acumulación de tokens zombies.
ThreadPoolExecutor (no signal.alarm) — seguro bajo gunicorn multi-worker. Timeout 10s evita cuelgues.
Cron mensual archiva contratos cumpliendo obligación fiscal MX. No se borran: se marcan archivados + bucket separado.
Cada transición en contratos_eventos. Cada acción de usuario en historial_acciones. Quién, cuándo, qué.