Cómo un producto de Nebula (Presupuesto, Contabilidad, Tesorería, Facturación…) ofrece sus reportes desde una sola ventana compartida del front: catálogo por producto, parámetros dinámicos declarados por reporte, motor JasperReports, vista previa progresiva con el formato real del reporte (el usuario va viendo las páginas mientras se generan y, si le sirve, descarga), reportes pesados monitoreados en el Centro de Tareas, archivos en MinIO, y una fachada por producto donde cada reporte agrega sus validaciones propias.
Versión: 0.3 (propuesta) · Fecha: 29 de octubre de 2026 · Arquitecto: Carlos Alberto Torres Camargo
Estado: PROPUESTA, pendiente de aprobación del arquitecto. Nada de esta API está construido.
Insumo visual: mockup «Lanzador Informes» (architecture/nebula-erp/design/mockups/Lanzador Informes.dc.html, commit e6740d2), recuperado del proyecto de Claude Design del arquitecto.
Cómo leer este documento. Cada afirmación sobre lo que existe cita su archivo (sección 17). Lo que se propone va marcado como propuesta. Lo que necesita una decisión del arquitecto está en la sección 16 y no se da por resuelto en ninguna otra parte.
Cada producto necesita reportes con parámetros propios (vigencia, rangos de rubros o cuentas, tipos de documento, niveles de agrupación, firmas…), pero la experiencia del usuario es una sola: elegir un reporte, diligenciar sus parámetros, ver el reporte y descargarlo. Este diseño separa las dos cosas:
Es la misma ley de los patrones canónicos de importación y exportación: el desarrollador aporta solo el dominio; el flujo lo gobierna la capa.
El problema que motiva la vista previa progresiva (arquitecto, 28-oct-2026): «algunos reportes son inmensos y a veces en sistemas como PowerBuilder uno lo puede ir viendo y si le sirve lo baja, entonces quiero evaluar si acá podemos hacer algo similar». La respuesta de este diseño es sí, con el formato real del reporte (sección 7).
Fuera de alcance: tableros BI y réplicas de lectura, que tienen su propio diseño (DISENO_TECNICO_REPORTERIA_BI_MULTITENANT.md).
| # | Requisito | Cita |
|---|---|---|
| RQ-01 | El componente de la ventana es compartido, vive en la librería shared/ui del front. |
«es un componente compartido así que irá en la lib shared-ui» |
| RQ-02 | Es genérico y dinámico: un módulo por producto para ver sus reportes. | «es un módulo por cada producto para ver sus módulos así que debe ser genérico y dinámico» |
| RQ-03 | Los reportes se cargan por producto. | «los reportes se cargan por productos» |
| RQ-04 | Cada reporte tiene parámetros dinámicos definidos. | «cada reporte tiene parámetros dinámicos definidos» |
| RQ-05 | Previsualización paginada. | «tiene previsualización paginada» |
| RQ-06 | Los reportes pesados van por tareas. | «reportes pesados van por tareas» |
| RQ-07 | Una clase fachada en cada producto donde se agregan validaciones específicas de un reporte. | «una clase fachada en cada producto donde se pueden agregar validaciones específicas para un reporte» |
| RQ-08 | El motor es JasperReports y el front renderiza su salida. | «sobre los reportes se usa el poder de jasper, el front debe poder renderizar eso» |
| RQ-09 | Ver el reporte mientras se genera y descargarlo si sirve. | «uno lo puede ir viendo y si le sirve lo baja» |
| RQ-10 | Monitoreo por el Centro de Tareas. | «incluye esa integración del centro de tarea para monitoreo» |
| RQ-11 | Arquitectura de buckets en MinIO. | «cómo sería la arquitectura de buckets en minIO» |
| # | Requisito | Dónde en el mockup |
|---|---|---|
| RM-01 | Catálogo del producto agrupado (en el ejemplo: «Ejecución» y «Consulta») con buscador. | this.reports, campo grupo; grupos en renderVals() |
| RM-02 | Contexto del catálogo: tipo de presupuesto (Gastos / Ingresos) y «Presupuesto de regalías». | tipo, regalia |
| RM-03 | Pestañas Filtros, Contenido, Niveles, Firmas y Vista previa, con insignia de errores o conteo por pestaña. | tabDefs |
| RM-04 | Parámetros que aparecen según el reporte, con banderas por reporte: rubro, rubroReq, doc, tercero, valor, docs, clasif, valorModo, niveles, forma. |
this.reports[*] |
| RM-05 | Tipos de parámetro: rango de fechas, rango de códigos con buscador, rango de consecutivos, tercero, valor mínimo, selección múltiple de tipos de documento, opción única (orden, valores, forma), mes, niveles ordenables con selección de datos por nivel. | rangos, opciones, nivelDefs |
| RM-06 | Validaciones visibles: fecha final anterior a la inicial, fecha fuera de la vigencia, rubro obligatorio, consecutivo final menor que el inicial, sin tipos de documento, sin niveles. | fechaBad, fechaOut, rubroFalta, docBad, docsFalta, nivFalta |
| RM-07 | Hasta cuatro firmas (nombre y cargo) al pie; las vacías no se imprimen. | firmas, texto «Los espacios vacíos no se imprimen» |
| RM-08 | Vista previa con encabezado de la entidad, parámetros aplicados, filas agrupadas y total. | pv, filas |
| RM-09 | Formato de salida (el estado inicial es pdf), botones Restablecer y Generar. |
fmt: 'pdf', genLabel |
| # | Regla | Fuente |
|---|---|---|
| RE-01 | Todo negocio es multitenant con consulta nativa y filtro de tres partes; paginación con NativeTenantPaginator. |
R-E01 |
| RE-02 | El API es agnóstica: la HU o la pantalla no recortan la firma; sin parámetro, valor canónico; fuera de dominio, 400. |
R-E09, patrón de importación §2 |
| RE-03 | status jamás como criterio de negocio. |
R-E02 |
| RE-04 | Periodo siempre YYYYMM. |
R-E16 |
| RE-05 | Todo texto visible con i18n ES y EN; nada desbordado a 1366. | R-G10, R-G15, R-G16 |
| RE-06 | Sufijos *Request, *Dto, *Response; Command prohibido. |
R-A05 |
| RE-07 | SimappeCommons y los repos de Catcsoft se consumen o se copian del lado de Nebula; no se modifican. | R-C01 |
| RE-08 | Lo nuevo de la capa común va en nebula-commons, y lo de contrato en nebula-models. |
Precedente: nebula-commons/.../tareas/ |
| RE-09 | La ventana se construye con el motor y el kit; lo que no soporten se arma con lo que hay, sin extender el kit. | R-G02 |
| RE-10 | libs/shared del front y el kit van con doble candado. |
R-C02 |
| RE-11 | Jamás secretos en repos; las credenciales de MinIO viven en config-server. | R-C05, R-C06 |
if por reporte en el front.JRDataSource propio que trae los datos por lotes con la consulta nativa del tenant (RE-01).Por qué una fachada. El ecosistema ya tiene una: CausacionMotorFacade (nebula-accounting-core), que expone un modo síncrono y uno por lotes vía Kafka detrás de una sola clase. La fachada de reportes sigue esa idea: una clase por producto que es la única puerta de sus reportes, hereda el flujo común y solo sobrescribe validarEspecifico. Un reporte nuevo es un ProcesoReporte más (su plantilla y su fuente) registrado en la fachada de su producto. Los nombres de esta sección son propuesta y se confirman al aprobar (R-A05).
Mismo contrato en cada servicio de producto. La base de la ruta sigue la convención del servicio (/api/v1/...); los nombres finales se fijan al aprobar.
| Operación | Método y ruta (propuesta) | Entrada | Salida |
|---|---|---|---|
| Catálogo del producto | GET /reportes |
Tenant del token; contexto opcional (p. ej. tipo de presupuesto) | Grupos con sus reportes y la definición completa de parámetros |
| Definición de un reporte | GET /reportes/{codigo} |
— | ReporteDefinicion |
| Fuente de un parámetro | POST /reportes/{codigo}/parametros/{parametro}/page-response |
Filtro y página | Opciones del buscador (rubros, cuentas, terceros, datos de un nivel), paginadas |
| Ejecutar | POST /reportes/{codigo}/ejecuciones |
ReporteRequest (parámetros) |
201 con ReporteEjecucionResponse: id de la ejecución y, si es pesado, id de la tarea |
| Estado de la ejecución | GET /reportes/ejecuciones/{id} |
— | Manifiesto: estado, páginas listas, páginas finales, total (al terminar), formatos disponibles |
| Página | GET /reportes/ejecuciones/{id}/paginas/{numero} |
— | HTML de la página; 404 si aún no existe |
| Recurso de una página | GET /reportes/ejecuciones/{id}/recursos/{nombre} |
— | Imagen o gráfico que la página referencia |
| Descargar | GET /reportes/ejecuciones/{id}/descargar?formato=pdf\|xlsx |
— | Archivo; 409 si la ejecución no ha terminado |
| Cancelar | POST /reportes/ejecuciones/{id}/cancelar |
— | Estado final; si es tarea, va por la orden del Centro de Tareas |
El mockup organiza los reportes de cada producto en grupos (en Presupuesto: «Ejecución» y «Consulta») y la ventana los pinta como secciones de la lista, en su orden, con el buscador por encima (RM-01). Esa organización la entrega la API: el front no la deduce ni la tiene escrita (Arquitecto, 29-oct-2026: «Fijase que so rportes tiene grupos como ejecucion, consulta asi que el api debe soportar esa organizacion para poder pintarla»). Es una API de Nebula, de cada producto; no es Simappe.
GrupoReporte, propuesta): codigo único dentro del producto, etiquetaClave (clave i18n del título, ES y EN), orden y la lista de sus reportes.ReporteDefinicion): grupo (código del grupo al que pertenece; obligatorio) y orden dentro del grupo.GET /reportes): devuelve los grupos ordenados, cada uno con sus reportes ordenados. Un grupo sin reportes visibles para el usuario no se devuelve. Un producto sin reportes devuelve la lista vacía y la ventana muestra el aviso de «sin informes».grupo no está declarado en la fachada del producto es un error de arranque, no un reporte suelto.Ejemplo de respuesta del catálogo (propuesta; las claves i18n son las que ya usa el front):
{
"producto": "budget",
"tituloClave": "BUDGET.INFORMES.TITULO",
"grupos": [
{
"codigo": "ejecucion",
"etiquetaClave": "BUDGET.INFORMES.GRUPO.EJECUCION",
"orden": 1,
"reportes": [
{ "codigo": "ejecucion", "grupo": "ejecucion", "orden": 1, "nombreClave": "...", "descripcionClave": "...", "parametros": [] },
{ "codigo": "modificaciones", "grupo": "ejecucion", "orden": 2, "nombreClave": "...", "descripcionClave": "...", "parametros": [] }
]
},
{
"codigo": "consulta",
"etiquetaClave": "BUDGET.INFORMES.GRUPO.CONSULTA",
"orden": 2,
"reportes": [
{ "codigo": "hoja-de-vida", "grupo": "consulta", "orden": 1, "nombreClave": "...", "descripcionClave": "...", "parametros": [] }
]
}
]
}
El front ya pinta esta forma. El lanzador construido (@nebula-shared/ui, rama local feat/bloque-2026-10-29, commit d4c1553a) declara los grupos del catálogo (grupos: { id; etiqueta }[], libs/shared/ui/src/lib/lanzador-informes/informes.model.ts:248) y el grupo de cada informe (grupo: string, informes.model.ts:215); hoy el catálogo de Presupuesto está en el código del front (informes-presupuesto.catalogo.ts) y pasa a llegar de este endpoint en la fase de integración.
Errores. Un 400 de parámetros devuelve la lista completa de errores, cada uno con el código del parámetro y la clave i18n del mensaje, para que la ventana marque cada campo y cada pestaña (RM-03). El contrato de error es el del ecosistema (SimappeException / SimappeError).
Parámetros que no viajan caen en su valorPorDefecto; un valor fuera de dominio es 400, nunca se degrada en silencio (RE-02).
Acceso. El front nunca va directo a MinIO: toda página y toda descarga pasan por el servicio, que verifica que la ejecución sea del tenant y del usuario del token (sección 9.4).
Los tipos salen de lo que pide el mockup (RM-05). Cada tipo tiene una validación común; la fachada agrega el resto. Los valores validados llegan a Jasper como parámetros de la plantilla.
| Tipo | Ejemplo del mockup | Validación común | Validación típica de la fachada |
|---|---|---|---|
RANGO_FECHA |
Fecha inicial y final | Final ≥ inicial; obligatoriedad | Dentro de la vigencia (fechaOut) |
RANGO_CODIGO |
Rubro desde / hasta, con buscador | Existe en la fuente; final ≥ inicial | Rubro obligatorio para «Hoja de Vida» (rubroReq) |
RANGO_CONSECUTIVO |
Documento desde / hasta | Solo dígitos; final ≥ inicial | — |
TERCERO |
Tercero | Existe en el tenant | — |
VALOR |
Valor mínimo | Numérico, ≥ 0 | — |
PERIODO |
Mes de «Valores del reporte» | YYYYMM (RE-04) |
Mes dentro de la vigencia |
SELECCION_MULTIPLE |
Tipos de documento | Al menos uno si es obligatorio; valores del dominio | — |
OPCION_UNICA |
Ordenar por, Valores (A la fecha / Al mes / Del mes), Forma (Detallado / Resumido) | Valor del dominio | Dependencias (si es «Al mes», pide el mes) |
NIVELES |
Catálogo, Dependencia, Fuente, Proyecto, CPC, ordenables, con datos por nivel | Al menos un nivel; niveles del dominio | Niveles válidos según el tipo de presupuesto |
FIRMAS |
Hasta cuatro nombre + cargo | Máximo declarado; vacías se omiten | — |
Pestaña. Cada parámetro declara en qué pestaña va (Filtros, Contenido, Niveles, Firmas). Si un reporte no declara parámetros de una pestaña, la pestaña no aparece (el mockup ya oculta «Niveles» cuando el reporte no los usa).
jasperreports-6.21.4.jar)| Pieza | Para qué |
|---|---|
AsynchronousFillHandle (createHandle(...), startFill(), cancellFill(), addFillListener(...), isPageFinal(int)) |
Llena el reporte en segundo plano, permite cancelarlo y saber si una página ya no cambia |
FillListener (pageGenerated(JasperPrint, int), pageUpdated(JasperPrint, int)) |
Avisa cada página que queda lista o que se actualiza |
JRDataSource |
Fuente de datos propia: Jasper la recorre fila a fila |
JRSwapFileVirtualizer |
Manda a disco las páginas ya hechas para que un reporte inmenso no llene la memoria |
SimpleReportExportConfiguration (setPageIndex, setStartPageIndex, setEndPageIndex) |
Exporta una página o un rango |
HtmlExporter, JRGraphics2DExporter |
Página a HTML o a imagen |
Precedente en el ecosistema: SimappeVote (Catcsoft) usa jasperreports 6.21.4 con un JasperReportEngine que compila el .jrxml del classpath (/reports/<nombre>.jrxml), lo guarda en caché y exporta a PDF, XLSX o CSV. No tiene vista previa por páginas. Se copia y adapta del lado de Nebula; no se modifica (RE-07).
AsynchronousFillHandle con la plantilla compilada, los parámetros y el JRDataSource del reporte, con JRSwapFileVirtualizer siempre activo.JRDataSource lee por lotes con la consulta nativa del tenant (NativeTenantPaginator o la vista plana del reporte); nunca se le da a Jasper una Connection (RE-01, principio 8).pageGenerated(n) el publicador exporta esa sola página a HTML (setPageIndex(n)) y la sube a MinIO; cada cierto número de páginas actualiza el manifiesto (páginas listas, sigue o terminó).isPageFinal en falso, p. ej. «página X de Y» o un total general), se reescribe cuando llega su pageUpdated final. El visor la refresca.JasperPrint serializado (reporte.jrprint). Las descargas PDF o XLSX se exportan desde ese archivo, una sola vez por formato, sin volver a consultar la base.cancellFill(): se detiene el llenado y se conserva lo que ya se publicó hasta su vencimiento.libs/shared/ui, dentro de la ventana de reportes (pestaña «Vista previa») y también se abre desde el Centro de Tareas.SONDEO_MS = 10_000 es el precedente; el valor para el visor se fija al aprobar).| Opción | A favor | En contra |
|---|---|---|
| HTML por página (recomendada) | Pesa menos; texto nítido y seleccionable; zoom sin pérdida | Depende de que la fuente esté disponible en el navegador |
| Imagen PNG por página | Fidelidad exacta, independiente del navegador | Pesa más; texto no seleccionable; zoom pierde nitidez |
.jrxml versionadas en el repo del servicio y compiladas una vez con caché, como en el precedente (D-03).concurrencia = 2 por defecto en TareasProperties).Un reporte pesado es una tarea más, y se ve, se cancela y se retoma desde el Centro de Tareas existente (DISENO_TECNICO_CENTRO_DE_TAREAS.md).
| Criterio (propuesta) | Resultado |
|---|---|
El reporte se declara pesado en su definición |
Siempre tarea |
estimarFilas(parametros) supera el umbral del producto |
Tarea |
| Resto | En línea, en la misma petición, con el mismo visor |
| Centro de Tareas (existente) | En un reporte (propuesta) |
|---|---|
Tipo de tarea (TipoTareaEnum: IMPORTACION, EXPORTACION, PROCESO) |
Tipo nuevo REPORTE (D-04) |
Proceso sin archivo de origen: ProcesoConTarea, idempotente |
El llenado es idempotente: repetirlo reescribe las mismas llaves en MinIO y no toca negocio |
Avance: totalRegistros, procesados, conError |
totalRegistros = filas estimadas; procesados = filas leídas; el mensaje dice las páginas listas |
Estados PENDIENTE → EN_PROCESO → COMPLETADA / FALLIDA / CANCELADA |
Igual. COMPLETADA_CON_ERRORES no aplica a un reporte (propuesta) |
| Órdenes: pausar, reanudar, cancelar, reintentar | Cancelar → cancellFill(). Reintentar una FALLIDA → vuelve a llenar desde el inicio (Jasper no reanuda). Pausar/reanudar no aplica: Jasper no pausa; el permiso de pausar queda en falso |
Descargar el resultado (/resultado) |
Acción «Ver reporte» que abre el visor con la ejecución, más descarga PDF por defecto |
Log de ejecución en tarea_logs |
Líneas de hitos: inicio, cada N páginas, fin, cancelación, fallo |
Bandeja del encabezado (/en-curso) |
Cuenta los reportes en curso igual que cualquier tarea |
| Hecho | Fuente |
|---|---|
Una instancia de MinIO por ambiente: minio-dev y minio-qa |
simappeconfig/dev-config/application-common.yml:621 y qa-config/application-common.yml:621 |
Bucket interno de la plataforma centrica-nebula-internal (single-tenant de SimappeAdmin) |
simappeconfig/dev-config/application-common.yml:624 |
SimappeCommons: un bucket por compañía simappe-{clientId}-{companyId}, llave {ambiente}/{tipoRecurso}/{archivo-fecha.ext}, URL prefirmada |
simappecommons/.../core/storage/MinioStorageService.java (upload, uploadToBucket) |
Tareas: un solo bucket nebula-tareas, llave <cliente>/<compania>/<tareaId>/<nombre> (origen.<ext>, resultado.<ext>) |
nebula-commons/.../tareas/almacen/TareasMinio.java (llave), MinioTareaSourceStore, MinioTareaResultStore |
| La llave de tareas no incluye la sucursal | TareasMinio.llave: solo getCustomerId() y getCompanyId() |
| Ningún código del ecosistema declara reglas de vencimiento en MinIO | Búsqueda de LifecycleConfiguration / setBucketLifecycle en backend/ (28-oct-2026): sin resultados |
El resultado de una tarea se descarga a través de nebula-tasks (GET /api/v1/tareas/resultado), no por URL directa |
TareaController.java:196 |
nebula-reportesUn bucket propio, separado de nebula-tareas, porque los reportes tienen otro volumen (cientos de páginas por ejecución) y otro vencimiento (las páginas de vista previa son efímeras). Mismo criterio de llave que las tareas, con la sucursal:
nebula-reportes/ (una instancia de MinIO por ambiente)
└── <cliente>/<compania>/<sucursal|0>/
└── <ejecucionId>/
├── manifiesto.json estado, páginas listas, páginas finales, total, formatos, reporte, usuario
├── paginas/
│ ├── 000001.html
│ ├── 000002.html
│ └── …
├── recursos/ imágenes y gráficos que referencian las páginas
├── reporte.jrprint JasperPrint serializado al terminar: base de toda descarga
└── exportes/
├── reporte.pdf se genera la primera vez que se pide
└── reporte.xlsx
| Prefijo | Vence | Por qué |
|---|---|---|
*/paginas/, */recursos/ |
Pocos días | Son vista previa; se regeneran si hace falta |
*/reporte.jrprint |
Igual que las páginas o algo más | Solo sirve para exportar sin volver a consultar |
*/exportes/ |
Lo que se decida para un archivo descargable | Puede que el usuario lo baje días después desde el Centro de Tareas |
La regla de vencimiento de MinIO por prefijo (lifecycle) no tiene precedente en el ecosistema; como el TTL de Mongo de tarea_logs, es un patrón nuevo que necesita autorización del arquitecto (D-10). Alternativa sin patrón nuevo: una limpieza programada en el servicio que borre las ejecuciones vencidas.
/api/v1/tareas/resultado. Alternativa: URL prefirmada de corta vida, como MinioStorageService (D-11).libs/shared/ui (@nebula-shared/ui, hoy 0.6.1), junto a precedentes de ventanas compartidas como export-modal y modals/. El acceso a datos va en libs/shared/data-access.lib-input, buscador con lupa); opciones únicas como selector segmentado; niveles y firmas armados con lo que el kit ya tiene (RE-09);#0c57a8; la construcción sigue el perfil 3.0 (Open Sans, lucide, #0E58A9) y se verifica a 1366, 1920 y en móvil (R-G02, R-G16).| Pieza existente | Relación |
|---|---|
NativeTenantPaginator (SimappeCommons) |
Lo usan el JRDataSource por lotes y las fuentes de los buscadores (RE-01). |
| JasperReports 6.21.4 en SimappeVote (Catcsoft) | Precedente del motor; se copia y adapta del lado de Nebula. |
ReportConfig, ReportSearchDto (SimappeCommons, api/v1/core/report) |
Modelo pensado para Jasper (connectCode, reportName, parameters, reporteBase64). Ningún servicio de Nebula lo usa. Se puede consumir; no se modifica. |
| Capa de exportación (SimappeCommons) | Sigue para exportar listados planos (/export); los reportes con formato van por Jasper. |
Centro de Tareas (nebula-commons/tareas, nebula-tasks, front) |
Ejecuta y monitorea los reportes pesados (sección 8). |
MinIO (nebula-tareas, simappe-*, centrica-nebula-internal) |
Convención de llaves que sigue el bucket nuevo (sección 9). |
CausacionMotorFacade |
Precedente de fachada. |
| Patrones canónicos de importación y exportación | Mismo estilo: capa común gobierna el flujo; el dominio aporta solo lo suyo. |
DISENO_TECNICO_REPORTERIA_BI_MULTITENANT.md |
Propone una réplica de lectura y un servicio nebula-reports, que no existe en backend/. Ver D-01. |
Parámetro afecta_presupuesto_publico |
Decide el tipo de cliente (R-E19); un catálogo puede filtrar reportes por sector. |
JasperPrint.JRSwapFileVirtualizer obligatorio; el disco temporal del contenedor debe alcanzar para el reporte más grande.YYYYMM; fechas en la zona del ambiente (America/Bogota).PermisoOperacion no tiene hoy un código de reportes (33 códigos: 16 de aprobar, 12 de anular, 3 de revertir, 1 de cierre y 1 de ejecutar). Ver D-07.nebula-reportes existe en cada ambiente (o se crea al arrancar, como TareasMinio hace con nebula-tareas).| # | Riesgo | Efecto | Mitigación (propuesta) |
|---|---|---|---|
| R-01 | Reporte inmenso en memoria | Caída del servicio | JRSwapFileVirtualizer siempre; tope de concurrencia de llenados |
| R-02 | Tareas largas reentregadas por Kafka | Reportes repetidos | Corregido en nebula-commons (MR !23, commit dd860ca, 08-oct-2026: reentrega a las 6 h, configurable); validar con un reporte largo |
| R-03 | Consultas pesadas sobre la base transaccional | Lentitud para todos | Lectura por lotes, tarea; réplica de lectura según el diseño BI si el volumen lo exige |
| R-04 | Total de páginas desconocido mientras genera | Usuario sin referencia | Indicador «N de ?» y avance por filas en el Centro de Tareas |
| R-05 | Páginas no finales («página X de Y», totales) | Página vista con datos incompletos | isPageFinal y reescritura en pageUpdated |
| R-06 | Volumen de objetos en MinIO | Disco del nodo | Bucket propio con vencimiento (D-10) o limpieza programada |
| R-07 | Estilos del HTML del reporte chocan con el ERP | Página deformada | Visor aislado |
| R-08 | Fuente distinta entre PDF y HTML | Lo previsto no es lo descargado | Extensión de fuentes Open Sans |
| R-09 | Jasper no pausa | Expectativa del botón Pausar | Permiso de pausar en falso para tareas REPORTE |
| R-10 | Reintentar recomienza desde cero | Tiempo perdido en reportes largos | Aceptado: Jasper no reanuda un llenado |
| R-11 | Validaciones duplicadas entre front y servidor | Reglas que divergen | El front solo usa la definición que entrega el servidor |
| R-12 | Cada producto inventa su contrato | Ventana compartida imposible | Contrato único en la capa común |
| R-13 | Extender el kit para niveles ordenables o el visor | Choca con R-G02 y el doble candado | Construir con lo que el kit ya ofrece |
| R-14 | Datos de prueba del mockup (municipio, NIT, firmantes) llegan al producto | Datos falsos en un documento oficial | Encabezado y firmas salen de parámetros del producto |
| Pieza | Repo | Estado |
|---|---|---|
Records y DTO del contrato: ReporteDefinicion, ParametroDefinicion, TipoParametroReporte, ReporteRequest, ReporteEjecucionResponse, manifiesto, error por parámetro |
nebula-models |
Por crear |
Tipo de tarea REPORTE |
nebula-models (TipoTareaEnum) |
Por crear (D-04) |
Capa común: fachada abstracta, ProcesoReporte, validador, orquestador, MotorReporteJasper (llenado asíncrono, virtualizador, publicador de páginas, exportes), JRDataSource por lotes, almacén nebula-reportes, autoconfiguración |
nebula-commons |
Por crear |
Dependencia jasperreports (6.21.4, la del precedente) y extensión de fuentes Open Sans |
nebula-commons |
Por agregar |
| Pieza | Dónde |
|---|---|
ReporteController con el contrato único |
Servicio del producto |
<Producto>ReportesFacade con sus validaciones específicas |
Servicio del producto |
Un ProcesoReporte por reporte, con su plantilla .jrxml y su consulta nativa (vista plana si hace falta) |
Servicio del producto |
| Fuentes de los buscadores | Reutilizar los page-response existentes donde ya los haya |
Vistas SQL de reporte, con su DDL (tablespaces _DATA / _INDEX) si se requieren |
Repo de scripts |
Primer candidato (mockup): Presupuesto, con seis reportes (Ejecución Presupuestal, Modificaciones Presupuestales, Ejecución y Modificaciones, Hoja de Vida, Relación de Documentos, Movimiento de Documentos).
| Pieza | Dónde |
|---|---|
Acción «Ver reporte» para tareas REPORTE y permiso de pausar en falso |
nebula-tasks (banderas) y front del Centro |
| Nombre del proceso por reporte en i18n | Repo de scripts (precedente postgres/simappe-admin/i18n/tasks/V2026_10_010__i18n_tasks_tipo_tarea_proceso.sql) |
| Pieza | Dónde |
|---|---|
| Ventana de reportes y visor | libs/shared/ui |
| Servicio de catálogo, ejecuciones, páginas y descargas | libs/shared/data-access |
| Opción de menú por producto | simappe_admin (menú), DEV y QA |
| Claves i18n de la ventana, el visor y cada reporte | Repo de scripts, DEV y QA |
| Pieza | Dónde |
|---|---|
Bucket nebula-reportes en cada ambiente, con su vencimiento |
MinIO de DEV y QA |
| Propiedades del bucket, umbral, concurrencia y vencimiento | config-server (simappeconfig) |
| Espacio en disco temporal para el virtualizador | Contenedor del servicio |
JRDataSource por lotes con tenant, publicación de páginas, páginas no finales, cancelación, exportes desde jrprint, tarea REPORTE en el Centro.| # | Decisión | Cita |
|---|---|---|
| D-02 | El motor de formato es JasperReports | Arquitecto, 28-oct-2026: «sobre los reportes se usa el poder de jasper, el front debe poder renderizar eso» |
| # | Decisión | Opciones visibles |
|---|---|---|
| D-01 | Dónde corre la generación | En el servicio de cada producto, o en un servicio de reportes aparte (el diseño BI nombra nebula-reports, que no existe) |
| D-03 | Dónde viven las plantillas y el catálogo | En el código de cada producto (como SimappeVote), o en tablas y MinIO por tenant (cada empresa con sus plantillas) |
| D-04 | Tipo de tarea | REPORTE nuevo (propuesto) o PROCESO |
| D-05 | Entrada en el menú | Una opción «Reportes» por producto, u otra |
| D-06 | Origen de las firmas y del encabezado | Parámetro del producto, de la compañía, o diligenciadas en cada generación |
| D-07 | Permiso | Un código por reporte, por producto, o el acceso a la opción de menú |
| D-08 | Formatos de descarga | PDF y XLSX, u otros |
| D-09 | Umbral de «pesado» | Valor y si es por producto |
| D-10 | Vencimiento en MinIO | Regla de vencimiento por prefijo (patrón nuevo) o limpieza programada; días por prefijo |
| D-11 | Acceso a páginas y descargas | A través del servicio (propuesto) o URL prefirmada de corta vida |
| D-12 | Formato de página de la vista previa | HTML (propuesto) o imagen PNG |
| Afirmación | Fuente |
|---|---|
| Modelo de reporte de Simappe orientado a Jasper | simappecommons/src/main/java/com/catcsoft/simappe/commons/api/v1/core/report/ReportConfig.java y ReportSearchDto.java |
Ningún servicio de Nebula usa Jasper ni ReportConfig |
Búsqueda de jasper en pom.xml y .java de backend/ (28-oct-2026): solo ReportConfig en SimappeCommons |
| Precedente Jasper | /mnt/personal/Catcsoft/Simappe/backend/business/SimappeVote/pom.xml:239-240 (jasperreports 6.21.4); .../vote/v1/report/component/JasperReportEngine.java (47 a 111); .../controller/GenericReportController.java (/catalog, /generate) |
| Clases y métodos de Jasper para llenado asíncrono y exportación por página | javap sobre ~/.m2/repository/net/sf/jasperreports/jasperreports/6.21.4/jasperreports-6.21.4.jar (28-oct-2026) |
No hay servicio nebula-reports |
Listado de /home/arquitecto/code/centrica/backend (28-oct-2026) |
| Paginación nativa | simappecommons/.../api/v1/core/query/NativeTenantPaginator.java |
| Exportación con escritores CSV, XLSX, PDF, TEXT, JSON, XML | simappecommons/.../api/v1/core/export/DefaultExportWriterResolver.java (línea 24; casos XLSX, PDF y CSV en las líneas 66 a 68) |
Tipos de tarea IMPORTACION, EXPORTACION, PROCESO |
nebula-models/.../tasks/tarea/enums/TipoTareaEnum.java |
| Proceso con tarea idempotente; concurrencia del trabajador | nebula-commons/.../tareas/proceso/ProcesoConTarea.java; TareasProperties.java |
| Bucket y llave de tareas | nebula-commons/.../tareas/almacen/TareasMinio.java (llave), MinioTareaSourceStore.java, MinioTareaResultStore.java; @Value("${nebula.tareas.bucket:nebula-tareas}") |
| Bucket por compañía y bucket interno | simappecommons/.../core/storage/MinioStorageService.java; simappeconfig/dev-config/application-common.yml:620-624 |
| MinIO por ambiente | simappeconfig/dev-config/application-common.yml:621 (minio-dev) y qa-config/application-common.yml:621 (minio-qa) |
| Sin reglas de vencimiento en MinIO | Búsqueda de LifecycleConfiguration / setBucketLifecycle en backend/ (28-oct-2026) |
| Descarga de resultado por el servicio | nebula-tasks/.../v1/tarea/controller/TareaController.java:196 |
| Sondeo de la bandeja | nebula-erp/.../centro-tareas/bandeja-tareas.component.ts:28 |
| Precedente de fachada | nebula-accounting-core/.../causacion/motor/component/CausacionMotorFacade.java |
| Permisos sin código de reportes | nebula-models/.../masters/permiso/enums/PermisoOperacion.java |
| Front: único precedente de reportes vacío | nebula-erp/libs/vault/src/lib/feature-vault/src/lib/reports/reports.component.ts (// TODO) |
| Librería compartida del front | nebula-erp/libs/shared/ui (@nebula-shared/ui 0.6.1) |
| Reentrega de Kafka | nebula-commons MR !23, commit dd860ca (08-oct-2026) |
| Versión | Fecha | Autor | Descripción |
|---|---|---|---|
| 0.3 | 2026-10-29 | Carlos Torres | Sección 5.1: el catálogo se organiza por grupos que entrega la API (GrupoReporte con código, etiqueta i18n y orden; ReporteDefinicion con grupo y orden), con ejemplo de respuesta; es API de Nebula, no de Simappe. |
| 0.2 | 2026-10-28 | Carlos Torres | Motor JasperReports (D-02 tomada); vista previa progresiva con el formato real del reporte (página a página mientras se genera, cancelar, descargar desde el reporte ya generado); integración con el Centro de Tareas para monitoreo (tipo REPORTE, órdenes, «Ver reporte»); arquitectura de almacenamiento en MinIO (bucket nebula-reportes, llaves, vencimiento, acceso); contrato por ejecuciones; decisiones D-10 a D-12. |
| 0.1 | 2026-10-28 | Carlos Torres | Propuesta inicial a partir del mockup «Lanzador Informes» y de los requisitos del arquitecto. Pendiente de aprobación. |