El viaje de un siniestro,
de la denuncia al pago.
DHLBC gestiona los siniestros del seguro de desgravamen de LBC Seguros — La Boliviana Ciacruz: cuando un deudor bancario fallece o queda inválido, el seguro paga el saldo de su deuda al banco. Esta presentación documenta el sistema completo — roles, flujo, pantallas, datos e integración con SISE — para que cualquier persona (o agente) lo entienda de principio a fin.
Qué es el sistema
Un banco presta plata. El deudor firma un seguro de desgravamen. Si muere o queda inválido, el seguro paga la deuda — y este sistema gestiona todo ese proceso.
Los bancos aliados (Banco Sol, Banco Fie, Banco Ecofuturo y Banco Estatal) envían periódicamente planillas Excel con las denuncias de siniestros de sus deudores. El sistema las carga masivamente, crea un caso por cada denuncia y lo asigna a un analista (round-robin). A partir de ahí el caso recorre un flujo de etapas: análisis documental asistido por OCR, gestión médica cuando hace falta, pronunciamiento (aprobar o rechazar), aceptación del banco tomador, tesorería (pago) y cierre.
En el camino, el sistema crea el siniestro en SISE (el core asegurador de Mapfre), genera cartas y documentos PDF, y mantiene la trazabilidad completa en un historial de 7 etapas por caso.
Arquitectura
Dos repositorios propios, tres sistemas externos y un pipeline de OCR.
Front — LBC.DESGRAVAMEN
Angular 17 (template daxa) · routing por hash (/#/…) · Angular Material + Syncfusion · sesión en sessionStorage · deploy Azure Static Web Apps.
API — LBC.DESGRAVAMEN.API
.NET 8 hexagonal · EF Core + SQL Server · JWT (un rol, 200 min) · Mapster · Result<T>/ErrorOr · Serilog+Seq · PDFs con iText (AcroForm).
Base de datos
SQL Server. Prod: DHLBC. QA: LBCDEV (snapshot de prod 30/12/2025 + pase WI #1229). ~45 entidades.
SISE (Mapfre)
Core asegurador. Recibe la creación del siniestro, sub-siniestros, solicitudes de pago y liquidaciones vía REST.
LDAP + SharePoint
LDAP autentica el login (uid={user},ou=users,dc=mycompany,dc=com). SharePoint/Graph almacena documentos (con alternativa local del WI #1240).
vision-gpt (Python)
Pipeline CLI de OCR: Google Cloud Vision + OpenAI leen los documentos escaneados y alimentan POST /Documents y POST /Batch.
Development, Testing, CI o LBCQA ejecuta EnsureDeleted() + EnsureCreated(): borra y recrea la base de datos completa. Production/Preprod solo corren BankInitial(). Nunca apuntar esos environments a una base con datos valiosos.Roles y usuarios
Cuatro roles operativos. El JWT lleva UN solo rol; el guard del front cierra la sesión si el rol intenta entrar a una ruta ajena.
| Rol (exacto en código) | Quién es | Landing tras login | Qué hace |
|---|---|---|---|
| Analyst | Analista de siniestros | /#/dashboard-page | El protagonista: gestiona la bandeja de 7 etapas (/#/home-page), completa el análisis documental, aprueba/rechaza pronunciamientos, envía a SISE, arma lotes y agrupa para tesorería. |
| Supervisor | Supervisor / administrador | /#/dashboard-page | Dashboard y reportes analíticos, administración de usuarios, configuración (FreeCover por banco, motivos de rechazo), reasignaciones. Es el rol "admin" — no existe un rol Administrator aparte. |
| Medical | Auditor médico | /#/medical-home-page | Evalúa los casos en Gestión Médica: emite el informe médico (PDF), pide documentación adicional o devuelve el caso. La decisión de aprobar o rechazar queda siempre en manos del analista. |
| Treasury | Tesorero | /#/tesorery-home-page | Recibe grupos de pago, registra el pago (comprobante vía dropzone) o lo rechaza, y descarga los soportes Excel/PDF del grupo. |
Usuarios del ambiente QA (snapshot de producción)
| Usuario | Nombre | Rol | Activo | Password QA | Casos asignados | Banco |
|---|---|---|---|---|---|---|
analista.extra4 | Analista Extra 4 | Analyst | ✓ | 123456 | 528 | Banco Sol |
andres.daleney | Andrés Daleney | Analyst | ✓ | desconocida | 301 | Banco Fie |
reina.santi | Reina Santi | Supervisor | ✓ | 123456 | 0 | — |
auditor.medico1 | Auditor Médico 1 | Medical | ✓ | 123456 | — | — |
auditor.medico2 | Auditor Médico 2 | Medical | ✓ | desconocida | — | — |
treasury1 | Tesorero 1 | Treasury | ✓ | 123456 | — | — |
test | UserNameTest | Analyst | ✗ | test | 0 | — |
| + 8 usuarios inactivos más (marcela.flores con 158 casos históricos, tahia.rojas, analista.extra1-3/5, leonardo.vela, gon.cons). La password se valida contra LDAP — no vive en la base. | ||||||
test tiene Active = 0 y aun así puede iniciar sesión: el login valida LDAP + existencia en la tabla User, pero no filtra por Active.El flujo del siniestro
Ocho etapas (ClaimState) y veinte estados finos (ClaimStatus). Las transiciones viven como guardas en el agregado Claim del dominio; la UI las dispara con acciones dinámicas que el propio backend decide por caso.
Atajos reales del flujo: FreeCover salta la Gestión Médica · un caso Rechazado cuya carta el tomador acepta va directo a Cierre (no pasa por Tesorería) · Recalculation devuelve un caso hacia atrás para recalcular.
Cómo nace un caso
El banco envía su planilla Excel. El analista la sube en Ingresar denuncia (chip "Carga masiva" — la carga individual fue eliminada del producto). El backend la parsea con un mapper específico por banco (ExcelMapperFactory), crea InsuranceFileHeader/Record y por cada fila un Claim con su TechnicalSheet y ClaimAnalysisData, en etapa Clasificación y análisis, status Assignated, repartido round-robin entre los analistas del banco. En paralelo, el pipeline vision-gpt hace OCR de los documentos escaneados y puebla los atributos que el analista después verifica en pantalla.
El análisis documental (gestion-page)
Es la pantalla data-driven del analista: renderiza un panel por documento del caso (Certificado de Defunción, Cédula, Hoja de Riesgo…), y dentro, un campo por cada DocumentField definido en la base — el orden lo decide DisplayOrder (del back) y las etiquetas se traducen por banco vía i18n (documentAttributes.{DocumentType}-{FieldName}). Los campos DataType = "select" se vuelven combos: Causa→Cobertura y País→Provincia (encadenados; el municipio lo auto-resuelve el back). Guardar y continuar persiste parcial (y recarga la página); Aprobar ejecuta el análisis y mueve el caso a En proceso.
Las acciones son del backend, no del front
Cada fila de la bandeja trae del backend su lista actions[] según el estado del caso (statementapproved, statementrejected, generaterejectionletter, reassign, view, delete, sendtosise…). El front solo las mapea a íconos con tooltip. Por eso dos casos de la misma bandeja pueden mostrar acciones distintas — y por eso las pruebas E2E localizan las acciones por su tooltip.
Gestión médica
Si el caso lo requiere (y no es FreeCover), el analista lo envía al médico (endpoint con typo real: PUT /{claimId}/medicalMamagement/user/{userId}). El médico ve su propia bandeja con estados MedicalEvaluation, MedicalInformationRequest y AdditionalMedicalInformation; emite el informe médico (PDF generado desde plantilla AcroForm), pide documentación adicional o devuelve el caso ("Devuelto por Médico"). El campo información adicional del pedido está acotado a 100 caracteres, validados en el handler del backend además del corte del formulario (#1275). La decisión final sigue siendo del analista.
Pronunciamiento, aceptación y tesorería
El analista aprueba o rechaza el pronunciamiento por caso. Los casos pronunciados se agrupan en lotes del mismo banco que van a Aceptación del tomador; ahí se aprueban o rechazan por caso. Los aceptados llegan a Tesorería, donde conviven dos agrupaciones distintas: "Agrupar para tesorería" (grupo de pago interno: Creado → En Tesorería → Pagado/Rechazado, con numeración tipo 001/2024) y "Agrupar liquidación" (solicitud masiva de pago a SISE). El tesorero registra el pago adjuntando uno o varios comprobantes en la misma operación (#1273/#1278; el historial registra un solo evento por caso, no uno por archivo), y el cierre del grupo lleva cada caso a Cierre — propagando el flag real de beneficiario adicional del caso (#1294).
Integración SISE
SISE es el core asegurador de Mapfre: el siniestro "oficial" vive ahí. DHLBC le crea el siniestro, el sub-siniestro y las solicitudes de pago.
- Crear siniestro —
POST /api/v1/app/Claims/Sise/CreateClaim/{claimId}. Se dispara con la acciónsendtosise, visible en la bandeja En proceso solo siSiseCreationStatus ∈ {Pending, Failed}. Consulta la póliza (número de riesgo, moneda), aplica la regla de fecha según el largo de la póliza y manda el payload snake_case — incluidoscod_pais_ocurrencia,cod_pcia_ocurrenciaycod_municipio_ocurrencia(el municipio se auto-resuelve desde la provincia elegida en el análisis). Entxt_responsableviaja el usuario SISE del analista responsable (User.SiseUserName, columna agregada en 2026-07; #1304): si el responsable no lo tiene configurado, la creación falla con error explícito — no hay fallback alUserNameni envío vacío. Estados:Pending → SuccessfulFromApp / SuccessfulManual / Failed. - Sub-siniestro — si el Excel del banco marcó beneficiario adicional (
HasAdditionalBeneficiary), tras crear el siniestro se intenta crear el sub-siniestro (montos Sepelio/PAPIT desdeBranchPolicy) y se persiste su carátula PDF como documento del caso. No es bloqueante: si falla, el siniestro principal queda creado. - Solicitud de pago / liquidación masiva — desde Tesorería, por caso o en bloque (
CreateBulkPaymentRequest). La liquidación masiva no exige mismo banco, pero sí estado Liquidado.
SiseNumber (ej. 2025-2746) en caso-page, editable por el analista junto con el número de solicitud de pago.Pantallas
Capturas reales del ambiente QA (2026-07-11), con la base migrada y datos de producción.

/#/. Usuario + contraseña contra LDAP. Selectores: #User, #Password, button[type=submit]. Cada rol aterriza en su landing.
/#/dashboard-page (Analyst y Supervisor). Reclamos por etapa, por cobertura (Invalidez/Muerte), por tomador y tiempos promedio de gestión.
/#/home-page (solo Analyst). Carrusel de 7 etapas con contadores, filtros por banco/tipo/estado, buscador, y acciones por fila (inline .btn-accion + menú .btn-acciones: Ver caso / Reasignar / Eliminar). La bandeja muestra los casos del analista logueado.
/#/home-page/gestion-page/{claimId}. Paneles por documento con campos data-driven (selector ideal: [data-slag='{DocumentType}-{FieldName}']), visor PDF del documento original a la derecha, "Guardar y continuar" y "Aprobar".
/#/caso-page/{id}/{back} (todos los roles). Cabecera con número de caso y número SISE (editable), riel de etapas, datos del asegurado, Analista responsable, comentarios, historial y documentación. El combo para cambiar de responsable lista solo analistas del banco del caso (#1302) — antes traía los de todos los bancos y elegir uno ajeno hacía fallar la asignación con HTTP 400. El médico ve esta pantalla sin lápices de edición.Otras pantallas documentadas en detalle en agentes/05-pantallas-front.md: pronunciamiento (lotes), aceptacion-page, tesorery-home-page (grupos, registro de pago), medical-home-page, admin-home-page (usuarios), reportes del supervisor, configuración (FreeCover, motivos), ingresar-denuncia (carga masiva con dropzone) y repositorio de casos.
El ambiente QA hoy
URL: https://dhdesa.lbc.bo/LBC/Aplicaciones/DHLbc/#/ (requiere VPN de LBC). Base LBCDEV reconstruida el 2026-07-11: snapshot de producción del 30/12/2025 + pase consolidado del WI #1229.
Casos por etapa (1.157 casos reales)
Bancos y parámetros
| Banco | FreeCover QA (Bs) | Pólizas / casos | Analista asociado | Mapper de carga | Parámetros del pase #1229 |
|---|---|---|---|---|---|
| Banco Sol | 174.000 | 53 BranchPolicy · mayoría de los casos | analista.extra4 (528 casos) | BancoSolExcelMapper | InsuredCode, DestinationBankCode, DestinationAccountNumber, LegalName |
| Banco Fie | 188.000 | 21 BranchPolicy | andres.daleney (301 casos) | BancoFieExcelMapper | ídem |
| Banco Ecofuturo | 280.000 | 8 BranchPolicy | sin analista activo vinculado en QA (fue el hallazgo H15/#1255) | BancoEcoFuturoExcelMapper | ídem |
| Banco Estatal | 0 | 0 BranchPolicy · 0 casos | — | ninguno — no está registrado en ExcelMapperFactory, así que hoy no puede cargar planillas | sin parámetros nuevos |
Las 82 BranchPolicy (53 + 21 + 8) son la configuración por póliza: banco, ramo, moneda, cartera, sepelio, PAPIT y tipo de pago (Parcial / Final). Ese último dato es clave y se malinterpreta seguido: el tipo_pago que viaja a SISE no se calcula por montos ni es un input del endpoint — es un atributo de la BranchPolicy (clave: banco + número de póliza SISE) que se copia a ClaimAnalysisData.PolicyholderPayment al crear el caso.
LBCDEV (QA), en BankParameter.FreeCoverAmount. El TestDataSeeder de los tests usa valores distintos (Bs 50.000 para Banco Sol y 30.000 para Fie y Ecofuturo): son fixtures, no configuración real. No tomar los del seeder como los del ambiente.Qué agregó el pase #1229
- 8 tablas nuevas: Country (12), Province (10), Municipality (10), Branch (2), Cause (33), Coverage (50), BranchPolicy (82), ParameterCatalog (4).
- 21 columnas nuevas con backfill — las críticas:
Claim.ResponsibleId(visible como "Analista responsable") yClaimAnalysisData.BranchCode/Portfolio(sin ellas, gestion-page queda EN BLANCO — el backfill matcheó 1.081/1.081). - 12 DocumentField nuevos tipo select (Causa/Cobertura/País/Provincia) y
DisplayOrderbackfilleado para el orden de los planes de pago por banco. - Reparación del drift histórico: 11 cambios de tipo, 58 índices, 4 FKs, 2 defaults.
Historia del producto
622 Work Items en 14 sprints, de julio 2024 a julio 2026. El sistema se construyó etapa por etapa, en el mismo orden del flujo.
Login LDAP, carga masiva de planillas, bandeja del analista, Pronunciamiento y Aceptación con lotes del mismo banco.
Ver Caso con historial de 7 etapas; Tesorería completa: grupos 001/2024, estados Creado → En Supervisor → En Tesorería → Pagado/Rechazado.
Cierre + Dashboard; perfil Médico (informe, doc adicional, devolución); perfil Tesorero; Supervisor con administración de usuarios y FreeCover fast-track por banco.
OCR sobre SharePoint, analytics del Supervisor, integración SISE (número de reclamo, liquidación masiva, banco Ecofuturo). Se elimina la carga individual.
Ubicación de ocurrencia (país/provincia/municipio hacia SISE, WIs #1174/#1175), sub-siniestros con carátula (#1177-#1179), acción dinámica "Enviar a SISE".
Plan de pagos data-driven por banco (PP-01..06), cartas multipágina y destinatario por banco (CR-02, #1242), repositorio local de archivos (#1240), cadena de tech-debt verificado con Playwright (#1236-#1252), y el pase a producción consolidado (DB-01, #1229).
Cosecha de los hallazgos de la corrida E2E y del QA visual, todos con test primero: cartas de rechazo y de documentación adicional con titular/codeudor reales y overflow multi-página sin dejar la firma sola (#1272, #1276, #1305) · tesorería con múltiples comprobantes por pago y notificación de error sin cerrar el diálogo (#1273/#1278, #1274) · combo de analistas filtrado por banco (#1302) · usuario SISE del responsable en txt_responsable (#1304) · beneficiario adicional real en el cierre (#1294) · límite de 100 caracteres en información adicional del médico (#1275) · plantillas de carga con "BENEFICIARIO ADICIONAL" marcado (#1300) y fixes de UI (#1288, #1292, #1293, #1295).
Abiertos conocidos
Estados verificados contra Azure DevOps el 2026-07-29. Los que no figuran acá se cerraron.
| WI | Estado | Qué falta |
|---|---|---|
| #1206 · OCR-01 | New | Excluir al Dr. Mauricio Guzmán B (CI 1650355) como asegurado detectado por el OCR: hoy el pipeline lo toma como parte del caso cuando en realidad firma el informe. |
| #1207 · CR-01 | New | Carta de rechazo: titular y codeudor. El síntoma ya está corregido — #1272 (Closed) reemplazó los "Pedro"/"Juan" hardcodeados usando ClaimPartiesResolver sobre ClaimAnalysisData.IsPrimaryHolder + TechnicalSheet.InsuredName. Pero el WI sigue abierto y su título arranca con "PENDIENTE*": pedía propagar las columnas PrimaryHolder/CoDebtor desde FileRecord hasta TechnicalSheet, cosa que no se hizo. Además FileRecord.PrimaryHolder/CoDebtor existen en la base pero ningún mapper de banco los puebla — quedan en cadena vacía. |
| #1210 · CFG-01 | New | Corregir los correos de notificación de cargas por banco. |
| #1250 · Seguridad | Active | clientSecret de SharePoint commiteado en appsettings.json. Rotar la credencial, no solo removerla del archivo — quedó en el historial de git. |
| #1191-#1198 | Active (8) | Fase 2 de aliados: perfiles Intermediary/Management/GeneralManagement, portal del aliado, módulo de denuncias, visibilidad documental, mark-read de notificaciones con validación de pertenencia y quitar los datos demo (ELEMENT_DATA) de caso-page. |
| #1303 | New | En las 7 pólizas DH+ (PLUS) de Banco Sol el beneficio del beneficiario adicional se calcula pero el sub-siniestro no llega a SISE: se saltea en silencio. Bloqueado por decisión de negocio. |
CoverageResponse tipada como wrapper en el front cuando el back emite array directo: Closed · #1272 — carta de rechazo con titular y codeudor reales: Closed · los 17 hallazgos de la corrida E2E (#1253-#1271): todos Resolved, pendientes de pasar a Closed tras validar en producción.Glosario esencial
Los términos mínimos para seguir una conversación del proyecto. El glosario completo (~80 términos) está en agentes/07-glosario.md.
- Desgravamen
- Seguro que paga el saldo de la deuda bancaria si el deudor muere o queda inválido. El beneficiario real es el banco.
- Denuncia / Caso / Siniestro
- La denuncia es el aviso del banco; el sistema la convierte en un caso (Claim); el siniestro es su representación oficial en SISE.
- Tomador
- El banco que contrató la póliza colectiva. "Aceptación del tomador" = el banco acepta el pronunciamiento.
- Etapa vs. estado
- Etapa = ClaimState (las 8 estaciones del riel). Estado = ClaimStatus (los 20 matices dentro de cada etapa, ej. Assignated, PendingPayment).
- FreeCover
- Umbral de monto por banco bajo el cual el caso es fast-track y salta la auditoría médica.
- Pronunciamiento
- La decisión formal del asegurador sobre el caso: aprobado o rechazado (con carta).
- Lote / Agrupación
- Conjunto de casos del mismo banco que avanzan juntos: lotes de pronunciamiento→aceptación, grupos de pago en tesorería, liquidaciones SISE.
- Carátula
- PDF resumen del sub-siniestro creado en SISE, persistido como documento del caso.
- Slag
- Clave
{DocumentType}-{FieldName}que identifica un campo del análisis; se usa para etiquetas i18n por banco y como selector de pruebas (data-slag). - Acción dinámica
- Acción por fila que decide el backend según el estado del caso (
actions[]); el front solo la dibuja. - SISE
- Core asegurador de Mapfre donde vive el siniestro oficial. DHLBC le crea siniestros, sub-siniestros y solicitudes de pago.
- Pase
- El paquete de cambios (SQL + binarios) que lleva un ambiente a la versión nueva. El pase consolidado actual es el WI #1229.
Cómo se prueba (E2E)
La guía operativa completa — paso a paso por rol, con selectores y asserts — está en agentes/08-guia-e2e-playwright.md. Esto es el mapa.
Las reglas de oro
- Sesión: vive en
sessionStorage; el guard cierra la sesión si el rol entra a una ruta ajena (ej. Supervisor →/#/home-page). Navegar mutandolocation.hash, nunca conpage.goto()a mitad de flujo. - Datos: las bandejas muestran solo los casos del analista logueado — usar
analista.extra4(528 casos, Banco Sol). Aceptación tiene 0 casos: hay que empujar uno por el flujo. - Descargas: la API SIEMPRE devuelve JSON base64; el evento download lo fabrica el front (
waitForEvent('download')funciona). - Timing: "Guardar y continuar" recarga la página (
window.location.reload()); "Aprobar" tiene un delay artificial de 3s+2s antes del redirect. - Textos exactos: los dialogs de confirmación tienen textos literales (con typos reales) — los asserts deben copiarlos tal cual.
Los 9 escenarios planificados
| # | Escenario | Rol | Cubre |
|---|---|---|---|
| E1 | Matriz de login | todos | 5 usuarios, logout, credencial inválida, landings por rol |
| E2 | Análisis documental completo | Analyst | gestion-page, combos encadenados, guardar parcial, aprobar → En proceso |
| E3 | Caso en proceso | Analyst | caso-page, comentarios, historial, pronunciamiento, carta de rechazo (PDF) |
| E4 | Envío a SISE | Analyst | acción sendtosise, estados SiseCreationStatus, carátula sub-siniestro |
| E5 | Gestión médica | Analyst Medical | envío al médico, informe (PDF), doc adicional, devolución |
| E6 | Pronunciamiento → Aceptación | Analyst | lotes mismo banco, aprobar/rechazar del tomador |
| E7 | Tesorería y cierre | Analyst Treasury | agrupar, enviar, pagar/rechazar con comprobante, cierre de grupo |
| E8 | Supervisor | Supervisor | dashboard, usuarios, configuración FreeCover, reportes, reasignación |
| E9 | Transversales | todos | repositorio, i18n, errores de consola por página, HTTP ≥ 400, rutas legacy sin guard |
evidencias/ (naming con los WIs/escenarios cubiertos) y se adjunta al Work Item correspondiente en Azure DevOps.