Skip to content
FINORA Academy
SistemaFINORA ERP

2. Arquitectura de iDempiere

Intermediate15 minVerified on Sep 25, 2026

This content is not available in your language yet.

iDempiere corre como un solo proceso Java (una JVM) que aloja, al mismo tiempo, el contenedor OSGi con todos los bundles, el servidor web Jetty, la interfaz ZK y la API REST. No hay microservicios separados: todo vive dentro de ese proceso, lo que simplifica el despliegue (un servicio systemd, idempiere.service, en la instalación de referencia de FINORA) a cambio de que toda actualización de un bundle de interfaz requiera reiniciar ese único proceso.

flowchart TB
    subgraph JVM["Un solo proceso Java (Equinox / OSGi)"]
        direction TB
        Jetty["Jetty embebido<br/>(servidor HTTP)"]
        ZK["org.adempiere.ui.zk<br/>(cliente web ZK)"]
        REST["idempiere-rest<br/>(API REST)"]
        Base["org.adempiere.base<br/>(modelo, reglas, Diccionario)"]
        Plugins["Plugins OSGi<br/>(FINORA LVE: base, fiscal, contable, nómina)"]
        Jetty --> ZK
        Jetty --> REST
        ZK --> Base
        REST --> Base
        Plugins -.->|"event handlers, fábricas, 2Pack"| Base
    end
    Browser["Navegador"] -->|HTTPS| Jetty
    Base --> PG[("PostgreSQL")]
  • El servidor es la JVM completa: arranca Equinox (la implementación de OSGi que usa iDempiere), que a su vez arranca todos los bundles instalados, entre ellos Jetty.
  • El contenedor OSGi (ver Tutorial 6) es lo que hace posible que el core, la interfaz ZK, el REST y los plugins de FINORA convivan como módulos independientes con sus propias dependencias declaradas, en vez de un único .war monolítico.
  • El cliente web ZK (org.adempiere.ui.zk, ver Tutorial 5) es la interfaz que ve una persona que entra por el navegador a /webui: ventanas, pestañas, grillas — todo generado en el servidor y enviado como fragmentos de interfaz actualizados por Ajax.
  • La API REST (com.trekglobal.idempiere.rest.api, ver Tutorial 10) expone el mismo modelo de datos y las mismas reglas de negocio bajo /api/v1, para integraciones que no pasan por el navegador (el portal de FINORA, apps, otros sistemas).
  • La base de datos es PostgreSQL. iDempiere no usa un ORM de terceros: el acceso a datos pasa por las clases PO/M* del propio core, que saben leer su estructura desde el Diccionario de Aplicación (AD_Table, AD_Column) y aplicar reglas de acceso por cliente, organización y rol antes de tocar la base.

Tomemos el caso más común: alguien completa una factura de compra desde la ventana Factura de Proveedor en el navegador.

sequenceDiagram
    participant N as Navegador (ZK)
    participant J as Jetty
    participant Z as org.adempiere.ui.zk
    participant M as Modelo (MInvoice, PO)
    participant E as Event handlers (core + FINORA LVE)
    participant D as PostgreSQL

    N->>J: Clic en "Completar" (petición Ajax)
    J->>Z: Despacha el evento del componente ZK
    Z->>M: MInvoice.processIt("CO")
    M->>E: dispara DOC_BEFORE_COMPLETE
    E->>E: FINORA: congela tasa BCV, calcula retenciones
    M->>D: UPDATE dentro de una transacción
    M->>E: dispara DOC_AFTER_COMPLETE
    E->>E: FINORA: materializa comprobante de retención
    M-->>Z: resultado (éxito o mensaje de error)
    Z-->>N: actualiza la ventana (estado, mensaje)

Los mismos pasos —validar, disparar eventos DOC_BEFORE_*/DOC_AFTER_*, escribir en una transacción, disparar DOC_AFTER_* de nuevo— ocurren exactamente igual si la petición llega por PUT /api/v1/models/c_invoice/{id} con {"doc-action":"CO"} en vez de por un clic en ZK (finora-erp-experience/idempiere/API_MAP.md, §6.2: “la misma acción de flujo de documento que el botón Process de ZK”). Esto es intencional: las reglas de negocio de FINORA se escriben una sola vez como event handlers sobre el modelo (PO), y valen tanto para la interfaz web como para integraciones REST (finora-lve/decisions/ADR.md, ADR-LVE-004).

En un servidor instalado, la carpeta plugins/ contiene un directorio por bundle (org.adempiere.base_13.0.0.<qualifier>/, org.idempiere.zk.iceblue_c.theme_13.0.0.<qualifier>/, com.trekglobal.idempiere.rest.api_1.0.0.<qualifier>/, y los bundles de FINORA LVE: com.finora.lve.base_<versión>/, etc.), listados en configuration/org.eclipse.equinox.simpleconfigurator/bundles.info (finora-erp-experience/idempiere/EXTENSION_GUIDE.md, §5). No hay dropins ni recarga automática de archivos: instalar o actualizar un bundle significa copiar su carpeta, editar bundles.info, y reiniciar el servicio.

Que todo viva en una JVM tiene una consecuencia que conviene conocer antes de planear una instalación: ZK guarda el estado de cada sesión (qué ventana tiene abierta cada usuario, en qué pestaña, con qué filtros) en el servidor, no en el navegador. Eso hace que poner dos instancias de iDempiere detrás de un balanceador de carga sin session affinity (afinidad de sesión) rompa la interfaz a mitad de uso — el balanceador podría mandar la siguiente petición del mismo usuario a una instancia que no tiene su sesión. La forma soportada de escalar la carga de un tenant grande es verticalmente (más memoria y CPU a la misma JVM) o repartiendo tenants distintos en instancias distintas, no repartiendo un mismo tenant entre varias instancias sin sticky sessions.