Saltar a contenido

Backend TiFacturaOnlineNext

Referencia técnica del backend de facturación electrónica AFIP (WSFEv1 + WSAA), migrado de Seam/JBoss a Spring Boot. Esta es la página ancla de la referencia: stack exacto, layout de paquetes, capas y build. Para el porqué de cada decisión de migración mirá Migración Seam → Spring; para las reglas que NO se pueden romper, Invariantes.

Datos medidos sobre el código

Todo lo de esta página está validado contra pom.xml, src/main/resources/application*.yml y el árbol src/main/java. Las versiones salen del pom.xml real, no de memoria.

Stack

Pieza Versión / valor
Lenguaje Java 17 (java.version en pom.xml; el compilar-jar.bat fuerza JDK 17 — NO compila con JDK 25)
Framework Spring Boot 4.0.7 (spring-boot-starter-parent)
GroupId / Artifact / Versión com.tipre / tifactura-spring / 2.0.0-SNAPSHOT
Empaquetado jar (finalName = tifactura-spring)
Clase main com.tipre.tifacturaonlinemanager.Application
Web spring-boot-starter-web + spring-boot-starter-tomcat (Tomcat embebido)
Persistencia spring-boot-starter-data-jpa / Hibernate 7.2.x (lo gestiona el BOM de SB 4.0), SQL Server
Driver DB com.microsoft.sqlserver:mssql-jdbc 12.8.1.jre11 (scope runtime)
SOAP Apache CXF 4.2.2 (cxf-spring-boot-starter-jaxws), contract-first vía cxf-codegen-plugin
Scheduling spring-boot-starter-quartz (Quartz 2.3.2 vía starter)
Seguridad spring-boot-starter-security (scaffold: todo permitAll, ver abajo)
Validación spring-boot-starter-validation (Jakarta Bean Validation)
Firma CMS / WSAA BouncyCastle bcprov-jdk18on + bcpkix-jdk18on 1.78.1
JSON legacy Jackson 1.x ASL 1.9.13 (org.codehaus.jackson, EOL — usado por las entidades, no se migra en Fase 1)
Utils commons-lang3 (versión vía BOM)
Namespace JEE jakarta.* (persistence, xml.ws, xml.bind, validation, servlet, jws)
CXF context path /TiFacturaOnlineManagerWS (cxf.path en application.yml)
Perfil por defecto dev (spring.profiles.default)

Bloques de dependencias por SPEC

El pom.xml mantiene comentados —rotulados por SPEC— los bloques pesados aún no abordados: Email (starter-mail + starter-thymeleaf), PDF (iText5 5.5.13.3, PDFBox 2.0.31, Flying Saucer 9.1.22, ZXing 3.5.3), cache de 2do nivel (hibernate-jcache + ehcache), y JAX-RS. Lo que está activo es el núcleo: web, JPA, security, CXF JAX-WS, Quartz y BouncyCastle. Las versiones de los bloques inactivos viven en <properties> pero no se resuelven hasta descomentar el bloque.

Layout de paquetes

Raíz: com.tipre.tifacturaonlinemanager. Convive con un paquete org.jboss.seam.* que es el seam-compat propio (un subset reimplementado de Seam 2.3.1 que da soporte a Component, EntityHome, EntityQuery, Controller, logging #0). Ver Seam-compat.

com.tipre.tifacturaonlinemanager
├── Application.java              @SpringBootApplication + @EnableScheduling (extends SpringBootServletInitializer)
├── model/                        entidades JPA (dominio) — ver modelo-dominio.md
│   ├── afip/                     TipoComprobante, TipoDocumento, TipoConcepto, TipoIva, TipoMoneda, TipoTributo
│   ├── trx/                      Trx, TrxDetalle, AlicuotaIva, Tributo, Opcional, ComprobanteAsociado, Caea, CaeaSinMovimiento
│   │   └── id/                   CaeaSinMovimientoId (clave compuesta @IdClass)
│   ├── error/                    TrxErrorLog
│   ├── job/                      JobEjecucion
│   ├── tarea/                    Tarea, ThreadSafety
│   ├── user/                     entidades de usuario
│   ├── EnteFacturador.java       comercio emisor (cert AFIP por comercio)
│   ├── SucPosPV.java             mapeo sucursal+POS -> PV CAE/CAEA de AFIP
│   └── CockpitStat.java          snapshot de métricas del cockpit
├── action/                      lógica de negocio portada del legacy
│   ├── db/                       SQLServerDialect (dialecto propio) — ver persistencia.md
│   ├── home/                     *Home (CRUD por entidad, extends EntityHome)
│   ├── list/                     *List (queries, extends EntityQuery)
│   ├── parent/                   ParentEntityHome, ParentEntityManager, ParentEntityQuery (núcleo de facturación)
│   ├── ws/                       servicios de negocio (FacturacionService, CaeaConsultaService, ...)
│   │   ├── client/               clientes AFIP migrados
│   │   │   ├── wsaa/             WsaaClient, WsaaTokenCache, credenciales
│   │   │   ├── wsfe/             WsfeCaeClient, WsfeCaeaClient, WsfeConsultaClient, WsfeDummyClient, ...
│   │   │   ├── common/           ArcaTlsContextFactory, HttpsSoapTransport
│   │   │   └── exceptions/       jerarquía de errores del cliente
│   │   ├── exceptions/           TrxNotFoundException, ParametroRequeridoException, ...
│   │   └── ws/                   jerarquía @WebFault legacy (compila la cadena de errores AFIP)
│   ├── job/, quartz/             jobs Quartz
│   └── utils/
├── ws/endpoint/                 endpoints SOAP CXF (TrxWsEndpoint, CaeaWsEndpoint, TfomWsEndpoint) + mappers gen<->modelo
├── web/                         controllers REST Spring MVC (CaeaWsRestController, VersionController, ...) + dto/
├── cockpit/                     panel de operación: controllers, métricas, ABM de SucPosPV
└── config/                      configuración Spring (ver abajo)

Capas

El backend conserva la estratificación del legacy Seam, montada sobre el seam-compat.

Capa Paquete Rol
Domain (entidades) model/** Entidades JPA y enums-tabla AFIP. POJOs anotados jakarta.persistence.*. Ver Modelo de dominio.
Homes action/home/** + action/parent/ParentEntityHome CRUD por entidad (extends EntityHome del shim). update() hace solo flush (invariante §5.2), sin merge.
Lists action/list/** + action/parent/ParentEntityQuery Queries (extends EntityQuery). getTrx usa order by id desc + maxResults 1 (invariante §5.3).
Services action/ws/** Negocio de facturación. ParentEntityManager orquesta idempotencia y persistencia en cascada de la Trx. FacturacionService, CaeaConsultaService, NotaCreditoReconciliacionService.
Clients action/ws/client/** Clientes AFIP: WSAA (login CMS, token cache) y WSFE (CAE, CAEA, consulta, dummy, último comprobante). TLS armado en AfipClientConfig. Ver Cliente AFIP.
Endpoints SOAP ws/endpoint/** SEI contract-first (CXF) que sirve los WSDL baseline de producción. Ver API SOAP.
Controllers REST web/**, cockpit/** Spring MVC. CAEA por REST, versión, y el cockpit. Ver API REST y Cockpit.
Config config/** Wiring Spring: seam-compat, CXF, AFIP, Quartz, seguridad, MVC, filtro de tráfico.

Paquete config

Clase Rol
SeamCompatConfig Bean entityManager (shared, FlushModeType.COMMIT) + reconocimiento de @Transactional de Seam.
SeamComponentRegistrar, SeamBridgeInitializer, SeamComponentRegistrar Registra los @Name de Seam como beans Spring y cablea el puente Component.getInstance.
SeamEventScope, SeamEventScopeFilter Scope EVENT de Seam por request HTTP.
SeamTransactionAnnotationParser Traduce @Transactional de Seam a la semántica de Spring.
AfipClientConfig Wiring de los clientes AFIP (SSLContext, transportes HTTPS, WSFE, WSAA, AfipCaeService).
AfipBatchConfig Configuración de procesamiento batch AFIP.
CxfSoapConfig Publica los 3 endpoints SOAP con el WSDL baseline.
QuartzConfig, AutowiringSpringBeanJobFactory Scheduling Quartz con inyección Spring en los jobs.
SecurityConfig Scaffold (HITO A): anyRequest().permitAll(), CSRF off. Seguridad real = SPEC-014.
WebConfig View controllers del cockpit (/cockpit, /cockpit-test, /cockpit-prod → forward a cockpit.html).
TrafficLoggingFilter Logea tráfico POS↔servicio al logger TRAFFIC (archivo traffic.log).

Seguridad: scaffold abierto

SecurityConfig deja todo permitAll con CSRF deshabilitado. Es el scaffold de HITO A para poder levantar y testear; la seguridad real (login DB, roles) está diferida a SPEC-014. El único candado operativo hoy es el header X-Cockpit-Secret del ABM del cockpit (env COCKPIT_ADMIN_SECRET, fail-closed), que NO es autenticación.

Build

Maven, parent spring-boot-starter-parent 4.0.7. Requiere JDK 17 (el compilar-jar.bat apunta a Eclipse Adoptium jdk-17 y advierte que NO compila con el JDK 25 default del sistema).

JAR ejecutable

# Compila a target/tifactura-spring.jar (sin tests)
mvn clean package -DskipTests

# Con tests (6 tests núcleo verde sobre H2 + gates)
mvn clean package

# Correr
java -jar target/tifactura-spring.jar

# Elegir perfil
java -jar target/tifactura-spring.jar --spring.profiles.active=prod

En Windows está el wrapper compilar-jar.bat (fija JAVA_HOME a JDK 17, corre mvn clean package -DskipTests y deja el JAR en target\).

Generación de código SOAP

cxf-codegen-plugin 4.2.2 corre wsdl2java en generate-sources sobre los 3 WSDL de src/main/resources/wsdl/ (TrxWS.wsdl, CaeaWS.wsdl, TiFacturaOnlineManagerWS.wsdl). Como comparten targetNamespace, cada uno se genera a su propio paquete (...ws.gen.trx, ...ws.gen.caea, ...ws.gen.tfom) para no colisionar los wrappers comunes. La salida va a target/generated-sources/cxf.

Nativo (GraalVM)

Hay hints AOT pero el build nativo NO está cableado

src/main/resources/META-INF/native-image/com.tipre/tifactura-spring/ contiene reflect-config.json, proxy-config.json y resource-config.json (pistas para GraalVM). Sin embargo, el pom.xml no declara el native-maven-plugin ni un perfil native. El artefacto soportado hoy es el JAR ejecutable; una imagen nativa requeriría agregar el plugin/perfil de GraalVM antes de mvn -Pnative native:compile.

Por dónde seguir