# Cómo conectar un programa antiguo a VeriFactu sin reescribirlo: arquitectura de Local Agent

> Instala Local Agent junto al sistema legacy y mantén `issueEnabled=false` durante diagnóstico. Ejecuta `doctor` para comprobar `/readyz`, SQLite y la capacidad read-only de la fuente sin llamar a preflight o issue. Elige DB, watch-folder o SFTP. DB exige driver verificado, una sola consulta SELECT, cursor estable y credenciales SELECT-only. Watch-folder identifica CSV/XLSX por hash y crea jobs por fila. SFTP es read-only, pinnea la host key y nunca modifica el remoto. Todos los jobs llegan al servidor como InvoiceIntent o mapped-source, pasan preflight y conservan una Idempotency-Key estable. Los leases, checkpoints y receipts permiten recuperar reinicios. Certificado y tenant permanecen server-side y AEAT producción se activa en un gate separado.

Canonical: https://kairoseth.com/es/blog/como-conectar-programa-antiguo-verifactu-local-agent
Product: [Software VeriFactu](https://kairoseth.com/products/kairoseth-fiscal)
Primary query: cómo conectar un programa antiguo a VeriFactu
Intent: informational-how-legacy-software-local-agent-verifactu-works
Published: 2026-10-07
Updated: 2026-10-07
Geographic scope: España
Geographic context: Local Agent y sus adapters son infraestructura reusable, pero esta guía se aplica a integración de facturación dentro del marco español SIF/VERI*FACTU. El gate de producción contrasta AEAT/BOE vigentes.

Local Agent cubre sistemas que no pueden usar un plugin o API server-to-server. Extrae datos por DB read-only, watch-folder o SFTP, los convierte en jobs durables y los envía por HTTPS al mismo pipeline de MappingProfile, preflight e idempotencia de Kairoseth Fiscal. El agente no recibe certificado AEAT ni autoridad fiscal y la emisión está desactivada por defecto.

El reto de un sistema legacy no es únicamente que sea antiguo: suele vivir dentro de una red local, depender de una base de datos que nadie quiere tocar, exportar ficheros en horarios concretos o ejecutarse en un PC sin una superficie de integración moderna. La solución no debería empezar abriendo puertos entrantes ni copiando un certificado fiscal a cada instalación. Local Agent v1 crea una frontera local deliberadamente pequeña. Mantiene una cola SQLite durable, observa una fuente con reglas read-only o no destructivas, aplica checkpoints y una identidad estable y se comunica por HTTPS saliente con Puente VeriFactu. El servidor conserva MappingProfile, tenant, certificado y ciclo fiscal. Así un ERP, TPV o programa de escritorio puede seguir siendo la fuente de hechos comerciales sin convertirse en la implementación de AEAT. Esta guía explica qué hace cada adapter, cómo se recupera de fallos y qué evidencia existe antes de considerar producción.

## 1. Cuándo utilizar Local Agent y cuándo no complicar la integración

Local Agent existe para ERP, TPV, aplicaciones de escritorio y sistemas de red local que no pueden integrarse de forma fiable mediante plugin nativo o API directa. No es la primera opción por principio. Si el producto ya dispone de una API server-to-server segura, esa ruta suele ser más simple. Si un volumen pequeño puede resolverse mediante CSV/XLSX manual con un buen proceso, tampoco hace falta instalar un servicio local. El agente aporta valor cuando la extracción debe automatizarse, sobrevivir reinicios y trabajar cerca de una fuente que solo existe en la red del cliente.

La decisión correcta sale del diagnóstico. Se identifica el evento que significa factura, su clave estable, la fuente de número/fecha, las tablas o archivos que contienen líneas e impuestos y el nivel de acceso disponible. El adapter se elige después. Este orden evita diseñar una solución tecnológica antes de saber si el sistema puede ofrecer datos consistentes. También permite utilizar Local Agent como bridge sin reescribir el programa: el origen sigue funcionando y la integración observa o consume una superficie controlada.

## 2. La frontera de seguridad: outbound-only y secretos fiscales en servidor

La foundation no abre ningún puerto HTTP entrante. createLocalAgentApiClient rechaza destinos remotos no HTTPS; HTTP inseguro solo se permite en localhost de desarrollo explícito. En producción, el cliente no necesita publicar un servicio de su red ni configurar una conexión iniciada desde Internet. El agente inicia comunicación hacia Kairoseth/Puente. Este patrón encaja mejor en redes pequeñas donde modificar firewall, router o políticas corporativas puede ser más arriesgado que instalar un proceso local con salida HTTPS.

El manifest exige `secrets_server_side=true`, `aeat_certificate_server_side=true` y `tenant_server_authoritative=true`. No se copia PFX, passphrase, clave privada o material de firma al agente. La configuración local tampoco acepta esos campos como parte válida de la operación. El agente necesita su credencial de bridge y secrets de origen cuando corresponda, por ejemplo una contraseña DB o SFTP referenciada mediante variable de entorno. La separación limita el impacto si el equipo local sufre una brecha: extraer datos no concede capacidad de firmar o cambiar tenant.

## 3. SQLite local convierte una extracción frágil en una cola durable

Leer una fila y enviarla inmediatamente crea una dependencia fuerte de la red. Si Kairoseth no responde o el PC se reinicia, resulta difícil saber qué se leyó, qué se intentó y qué identidad corresponde a cada retry. Local Agent inserta primero operaciones en SQLite. El archivo se protege con modo 0600 en POSIX y conserva jobs, checkpoints y receipts. El worker toma leases, procesa con backoff acotado y marca blocked los fallos no retryable. La fuente y el transporte dejan de estar unidos por una única llamada sin memoria.

La Idempotency-Key local se deriva de `sourceId + sourceKey`. Eso obliga a que el adapter defina una identidad estable de origen: cursor DB, fila/fingerprint, evento o combinación equivalente. Un crash después de una respuesta perdida puede reintentar usando la misma clave. El servidor mantiene además su idempotencia fiscal, por lo que la cola local no sustituye al core. Esta doble capa permite recuperar fallos entre extracción, HTTP y persistencia de respuesta sin inventar nuevas identidades en cada proceso.

## 4. Cómo funciona la extracción read-only de PostgreSQL, MySQL/MariaDB y SQL Server

`pollDatabaseSource()` ofrece un camino común sin incrustar fiscalidad en el driver. La configuración define sourceId, profileId, cursorField y una consulta. El driver debe verificarse como read-only, la query debe ser exactamente una sentencia SELECT y el tamaño de página está acotado a 1.000 filas. Cada resultado se transforma en un job `mapped-source` y se inserta en la cola antes de avanzar el checkpoint. Si el proceso cae en ese intervalo, volver a leer una fila produce la misma sourceKey y por tanto la misma identidad idempotente.

Los drivers específicos añaden evidencia del motor. PostgreSQL utiliza un pool `pg` y ejecuta verificación/extracción dentro de `BEGIN READ ONLY`. MySQL/MariaDB utiliza `mysql2/promise` y `START TRANSACTION READ ONLY`. SQL Server utiliza `mssql`, comprueba permisos/rol y mantiene la restricción SELECT-only. Producción debe crear un usuario limitado aunque el código ya rechace SQL de escritura. CI ejecuta compatibilidad contra PostgreSQL 16, MySQL 8.4, MariaDB 11.4 y SQL Server 2022, y ese conjunto es la matriz que podemos afirmar como probada.

## 5. El checkpoint indica progreso de extracción, no estado fiscal

Un cursor de base de datos o receipt de archivo responde a una pregunta local: ¿hasta dónde hemos leído la fuente? No responde si una factura fue aceptada, rechazada o sigue pendiente en el motor fiscal. Local Agent documenta esta separación expresamente. El checkpoint solo avanza después de insertar el job durable. A partir de ahí, la cola y el servidor gestionan emisión y reconciliación. Confundir checkpoint con estado fiscal llevaría a saltar filas o a dar por aceptada una operación simplemente porque ya fue extraída.

Esta distinción también facilita soporte. Si una fila no aparece en la cola, se investiga la fuente y checkpoint. Si está en cola bloqueada, se revisa preflight o error de transporte. Si tiene recordId, se reconcilia en servidor. Cada fase conserva su propia evidencia y no intenta sustituir a la siguiente. En sistemas legacy, donde la observabilidad original suele ser limitada, esta segmentación crea un recorrido más comprensible sin escribir metadata de vuelta en la base del cliente.

## 6. Watch-folder estabiliza, identifica y procesa cada revisión de fichero

Un programa que exporta CSV o XLSX puede integrarse sin acceder a su base. `scanWatchFolder()` detecta extensiones permitidas y calcula SHA-256 en streaming. Nombre + hash forman la identidad de la revisión. Un archivo idéntico no se vuelve a encolar; si cambia el contenido, aparece una nueva revisión. El pipeline mueve un archivo estable desde inbox a processing, lo parsea con el conector de archivos existente y crea jobs independientes por fila, cada uno bajo MappingProfile y preflight del servidor.

Al finalizar todas las filas, el lote se mueve a processed o error. Los jobs terminales redactan automáticamente payload_json y cuerpos de respuesta, conservando sourceId, sourceKey, fingerprint, Idempotency-Key, estado y recordId. Esto reduce retención de datos crudos sin perder evidencia suficiente para rechazar replays conflictivos. El archivo original archivado mantiene una política de retención controlada por operador; el default es keep y cualquier borrado automático necesita una configuración explícita de días y metadata válida.

## 7. SFTP amplía watch-folder a un origen remoto sin mutar el servidor del cliente

El adapter SFTP existe para sistemas capaces de depositar archivos en un servidor gestionado pero incapaces de llamar a la API. La identidad del host se pinnea mediante fingerprint SHA-256. Se aceptan contraseña o private key como autenticación, pero esos secrets permanecen en runtime y no se escriben en queue payloads ni manifests. Solo se procesan ficheros regulares CSV/XLSX dentro de límites de edad/tamaño. Los bytes descargados se validan contra tamaño listado y content hash antes de entrar en el inbox local.

La ruta es deliberadamente no destructiva. Utiliza `list()` y `get()`; no sube, renombra o elimina el archivo remoto. Cada combinación de directorio, nombre, tamaño y modificación tiene un receipt SQLite durable que evita staging repetido tras reinicios. CI levanta un servidor SFTP real, pinnea una host key Ed25519 generada, demuestra que upload es rechazado, descarga un CSV y comprueba que un segundo poll es idempotente. Ese test prueba transporte; la idempotencia fiscal sigue perteneciendo a los jobs y al servidor.

## 8. doctor, status, once y start separan diagnóstico de ejecución

El runtime unificado puede ejecutar fuentes watch-folder, DB o SFTP con el mismo proceso. `doctor` comprueba readyz, store local y capacidad read-only de la fuente sin preflight ni issue. `status` lee únicamente metadata operativa local y no necesita secretos runtime. `once` ejecuta un ciclo y `start` mantiene el loop continuo. Los dos comandos de ejecución utilizan un lock de instancia única para evitar que dos procesos trabajen simultáneamente sobre el mismo data directory.

Esta interfaz mejora onboarding. El instalador puede desplegar código y configuración, ejecutar doctor y entregar un resultado verificable antes de habilitar emisión. La configuración JSON schema v1 debe ser privada; en POSIX se exige modo 0600. Bridge API key, contraseña DB y credenciales SFTP se referencian mediante nombres de variables de entorno en lugar de escribirse inline. Certificado AEAT y private key no son opciones aceptadas. La instalación puede quedar completamente preparada en modo fail-closed hasta una decisión posterior.

## 9. El bundle portable y los instaladores nativos hacen explícita la matriz de plataforma

El artefacto de Local Agent es un ZIP JavaScript reproducible con commit fuente de 40 caracteres, manifest, fingerprint de contenido y sidecar SHA-256. La misma descarga se prueba en runners nativos Linux x64, Windows x64, macOS Intel x64 y macOS ARM64. Cada smoke instala dependencias exactas, ejecuta status y doctor con issueEnabled=false. La compatibilidad declarada se apoya así en el mismo ZIP que después se distribuye, no en builds diferentes por plataforma.

La integración de startup usa herramientas nativas: systemd en Linux, launchd en macOS y Task Scheduler en Windows. Código, configuración y datos se ubican en rutas separadas. Reinstalar conserva configuración salvo reemplazo explícito; uninstall elimina startup/código pero conserva secrets y estado local. En Windows se endurecen ACL de configuración/datos y en POSIX archivos sensibles utilizan 0600. Este modelo facilita soporte sin esconder un wrapper de servicio de terceros dentro del runtime.

## 10. Upgrade valida estado y backup; rollback es code-only por diseño

Antes de activar código nuevo, el guard comprueba manifest SHA-256 y bytes, fingerprint global, rango de schema de estado, Node compatible, lock del data directory y SQLite quick_check. Si existe agent.sqlite crea un backup verificado y compara counts de jobs/checkpoints/receipts. Solo después cambia el release actual. Esto protege contra upgrades que podrían interpretar mal el estado durable y evita reemplazar código mientras otro proceso está usando la cola.

Rollback cambia el symlink/junction `current` al release previo y deliberadamente no restaura SQLite. El backup se conserva como evidencia/recovery material para una decisión explícita, porque restaurar automáticamente una base puede borrar jobs creados después del upgrade. Esta distinción es importante en un bridge fiscal: volver a código antiguo y volver a estado antiguo son operaciones diferentes. El procedimiento favorece preservar identidad e historial frente a una restauración automática destructiva.

## 11. La activación final sigue siendo un gate separado del despliegue local

`issueEnabled=false` es el punto de partida fail-closed para la configuración de referencia. Esto permite instalar, diagnosticar, probar acceso read-only, inspeccionar archivos y validar MappingProfile sin crear registros fiscales. La preparación técnica se vuelve reversible: si una vista SQL no contiene la fecha correcta o un fichero no tiene una columna, se corrige antes de activar. Incluso el smoke del bundle mantiene issue desactivado para que la prueba de plataforma no se confunda con emisión.

Cuando la integración local está lista todavía falta el gate de AEAT producción. Se comprueban certificado, identidad, configuración fiscal, evidencias, normativa vigente y autorización explícita. Local Agent no recibe esos secretos ni puede concederse permisos a sí mismo. Tampoco un CI verde equivale a certificación oficial. Su valor es demostrar que el transporte local, recuperación y aislamiento cumplen el contrato probado; la decisión fiscal final sigue perteneciendo al control de producción.

## Conclusiones

- Un sistema sin API puede adaptarse por DB read-only, watch-folder o SFTP sin convertir Local Agent en motor fiscal.
- La cola SQLite, leases, checkpoints y sourceId/sourceKey hacen durable la extracción y los retries.
- Producción DB exige usuarios SELECT-only; la validación de código es defensa en profundidad.
- SFTP es no destructivo y watch-folder usa fingerprint de contenido para identificar revisiones.
- Instalación y doctor pueden completarse con issueEnabled=false; AEAT producción permanece en un gate separado.

## Sources

- [Local Agent v1](https://github.com/Emmakex/puente-verifactu/blob/main/packages/local-agent/README.md) — Kairoseth / Puente VeriFactu
- [Universal Integration Matrix](https://github.com/Emmakex/puente-verifactu/blob/main/docs/universal-integration-matrix.md) — Kairoseth / Puente VeriFactu
- [Contrato API v1](https://github.com/Emmakex/puente-verifactu/blob/main/docs/api-contract.md) — Kairoseth / Puente VeriFactu
- [AEAT — Sistemas Informáticos de Facturación y VERI*FACTU](https://sede.agenciatributaria.gob.es/Sede/iva/sistemas-informaticos-facturacion-verifactu.html) — Agencia Estatal de Administración Tributaria

## External resources

- [Portal oficial AEAT SIF / VERI*FACTU](https://sede.agenciatributaria.gob.es/Sede/iva/sistemas-informaticos-facturacion-verifactu.html): Información técnica y referencias normativas oficiales.

## Producto relacionado

- [Software VeriFactu](https://kairoseth.com/products/kairoseth-fiscal): Software VeriFactu adaptable para conectar WooCommerce, PrestaShop, ERP, CRM, Excel, software propio y sistemas locales sin sustituir el sistema de origen.
- [Solicitud personalizada](https://kairoseth.com/custom-requests)
