1. Visión General
El Motor de Reglas de Negocio es un sistema centralizado y dirigido por datos, diseñado para gestionar y ejecutar lógica de negocio de forma dinámica sin necesidad de cambios en el código ni despliegues. Desacopla la lógica central de la aplicación de las reglas que gobiernan sus procesos, permitiendo una mayor flexibilidad, escalabilidad y un mantenimiento más sencillo.
Objetivos Clave:
Agilidad: Modificar la lógica de negocio (ej. criterios de aprobación de crédito, cálculo de comisiones, reglas de validación) simplemente cambiando datos en la base de datos.
Centralización: Consolidar las reglas de negocio en un único repositorio manejable.
Desacoplamiento: Separar la lógica de negocio del código de la aplicación para una arquitectura más limpia.
Adaptabilidad: Permitir que las reglas tengan un alcance específico para diferentes mercados, lenders, países u otros contextos.
El motor está diseñado para ser implementado progresivamente junto a la lógica existente ("legacy"), controlado por una Feature Flag para una transición segura y controlada.
2. Conceptos Fundamentales
El motor se construye sobre conceptos clave que definen cómo se estructura y aplica una regla.
Concepto | Descripción |
Modelo de Negocio | Un esquema de alto nivel que define el marco operativo para un lender en un mercado específico (ej. |
Regla de Negocio | La entidad central que contiene la lógica. Vincula un módulo, condiciones, acciones y parámetros. Cada regla tiene un código único, versión y prioridad para gestionar su orden de ejecución. |
Módulo | El área o proceso específico del sistema donde se aplica una regla (ej. |
Procedimiento | Un subproceso dentro de un Módulo. Permite una aplicación más granular de las reglas. Por ejemplo, dentro del módulo |
Condición | La prueba lógica que el motor evalúa. Consiste en un campo, un operador y un valor (ej. |
Acción | El resultado si las condiciones de una regla se cumplen. Ejemplos: |
Parámetro | Valores configurables y reutilizables usados en las condiciones o acciones (ej. |
Alcance (Scope) | Define el contexto donde una regla aplica. Una regla puede ser global o específica a un país, mercado, lender o asociación. |
3. Esquema de la Base de Datos
Toda la lógica del motor de reglas se almacena en un conjunto de tablas relacionadas en la base de datos.
business_rule
La tabla central para cada regla. Conecta todos los demás componentes.
model business_rule {
id Int @id @default(autoincrement())
code String @unique
name String
description String? @db.VarChar(255)
business_model_id Int
module_id Int
type_id Int
procedure_id Int
status Boolean @default(true)
configurable Boolean @default(true)
level Int?
version Int @default(1)
priority Int @default(1)
// ... relations
}
priority: Define el orden de ejecución para las reglas dentro del mismo módulo/procedimiento.configurable: Determina si la regla puede ser actualizada.version: Permite un seguimiento histórico de los cambios en las reglas.
Tablas de Soporte
business_rule_module: Define los módulos del sistema donde aplican las reglas (ej. code: 'MOD_GES_COM', name: 'Gestion Compradores').business_rule_procedure: Define procedimientos específicos dentro de un módulo.business_rule_type: Categoriza el tipo de regla (ej. 'Regla', 'Validación').business_rule_condition: Almacena las condiciones para una regla.business_rule_parameter: Contiene los parámetros configurables para una regla.business_rule_action: Define la acción a tomar si las condiciones de una regla se cumplen.business_rule_scope: Especifica el alcance de aplicación de una regla (ej. market_id, country_id).
4. Funcionamiento - Detalles de Implementación
4.1. Invocación y Feature Flag
El motor de reglas se inicia a través de la función checkRuleEngine. Antes de la ejecución, se verifica una Feature Flag de GrowthBook para determinar si el motor debe ser utilizado.
Feature Flag:
USE_RULE_ENGINE
Si la bandera está desactivada, el motor omite la evaluación y el sistema utiliza la lógica legacy.
Ejemplo de Invocación:
import { checkRuleEngine } from "./engine-Rules";
// Objeto de contexto con todos los datos necesarios para la evaluación
const context = {
name: "", // Nombre de la asociación
lender_id: 0,
market_active: true,
// ... otros campos del formulario
};
// Llamada al motor
const result = await checkRuleEngine({
context: context,
associationId: 1, // ID de asociación aplicable
module: "Gestion Asociaciones",
procedure: "Alta Asociación",
level: 1
});
if (!result.valid) {
throw new Error(result.message);
}
4.2. Obtención de Reglas
Al ser invocado, la clase RuleEngine consulta la base de datos usando getRulesFromDb. Obtiene todas las reglas activas (status: true) que coinciden con module, procedure, y level proporcionados.
4.3. Validación del Contexto
Antes de evaluar las reglas, el motor realiza un paso crítico de validación de contexto. Analiza todas las reglas a evaluar e identifica cada campo variable utilizado en las condiciones (ej. buyer.age). Luego, verifica que estos campos existan en el objeto context pasado durante la invocación.
Información
Esta validación es crucial. Si falta algún dato requerido en el contexto, el motor lanzará un error Missing parameters in context, previniendo comportamientos inesperados o evaluaciones incorrectas.
4.4. Lógica de Evaluación
El proceso de evaluación está diseñado para ser robusto y determinista.
División por Acción: El motor primero filtra las reglas según su tipo de acción.
Rechazo Primero: Evalúa todas las reglas con acción de tipo "reject" (
rechaza). Si alguna de estas reglas cumple todas sus condiciones, el motor se detiene inmediatamente y devuelve un resultado{ valid: false, message: "..." }.Accionable Segundo: Si ninguna regla de rechazo fue activada, el motor evalúa las reglas de tipo "actionable" (
accionable). Si una de estas reglas se cumple, devuelve un resultado{ valid: true, message: "..." }.Éxito por Defecto: Si ninguna regla se activa, el motor devuelve
{ valid: true }, lo que significa que el proceso puede continuar.
5. Integración con Frontend: Validación Dinámica con Yup
Una característica clave de esta arquitectura es la capacidad de generar esquemas de validación para el frontend directamente desde las reglas de negocio. Esto asegura que las validaciones en la UI (ej. en un formulario) estén siempre sincronizadas con la lógica del backend.
Esto es gestionado por la función utilidad buildRuleConditions, que construye un esquema de validación Yup.
Cómo funciona:
Las reglas se obtienen de la base de datos, tal como en la evaluación del backend.
La función
buildRuleConditionsitera a través de las reglas para un campo dado (ej.name).Traduce la condición de cada regla a su validador Yup correspondiente.
Ejemplos de Mapeo:
Condición de la Regla | Equivalente en Yup |
|
|
|
|
|
|
|
|
|
|
| Un |
6. Anexo: Listados de Referencia
A continuación se encuentran los catálogos actuales de Módulos, Procedimientos y Tipos de reglas definidos en el sistema.
Módulos de Reglas de Negocio
ID | Código | Nombre |
1 |
| Gestion Compradores |
2 |
| Gestion Proveedores |
3 |
| Gestion Lender |
4 |
| Reglas de oferta crediticia |
5 |
| Gestion Mercado |
6 |
| Gestion Asociaciones |
7 |
| Gestión Lenders |
8 |
| Gestion Modelo de negocio |
9 |
| Gestion Relaciones y oferta crediticia |
10 |
| Transaccional financiero |
Procedimientos de Reglas de Negocio
ID | Código | Nombre |
28 |
| Alta Asociación |
29 |
| Edición Asociación |
45 |
| Operatoria Inactivacion Asociación |
46 |
| Operatoria Activacion Asociación |
Tipos de Reglas de Negocio
ID | Código | Nombre |
1 |
| Regla |
2 |
| Validación |
7. Cómo Crear una Nueva Regla de Negocio (Ejemplo Real)
Usaremos un ejemplo real del módulo Gestion Asociaciones: la regla RULE-60001, que valida que el nombre de la asociación sea obligatorio.
Regla: "El campo Nombre de la asociación debe ser completado".
Módulo:
Gestion Asociaciones(ID 6).Procedimiento:
Alta Asociación(ID 28).Acción:
Rechazael guardado si la condición se cumple.
Así se registrarían los datos en la base de datos:
Tabla
business_ruleid: 60001code: "RULE-60001"name: "El campo Nombre de la asociación debe ser completado "module_id: 6procedure_id: 28type_id: 2business_model_id: 1status: true
(Fuente: gestion_asociaciones_rules.ts)
Tabla
business_rule_conditionrule_id: 60001field: "name"operator: "==="value: "Nulo"description: "name = Nulo"
(Fuente: gestion_asociaciones_conditions.ts)
Tabla
business_rule_parameterPara esta regla específica, no se necesitan parámetros, ya que el valor de la condición (
Nulo) está directamente definido.
Tabla
business_rule_actionrule_id: 60001action_type: "Rechaza"message: "El nombre nombre de la asociación es requerido"
(Fuente: gestion_asociaciones_actions.ts)
Tabla
business_rule_scoperule_id: 60001Aquí se vincularía la regla a un
lender_id,market_id,country_idoassociation_idespecífico. Si no se crea un registro en esta tabla para la regla, se considera de alcance global.
Con estos registros, la próxima vez que se llame al motor para el procedimiento de Alta Asociación y el campo name en el context sea nulo o vacío, el motor rechazará automáticamente la operación con el mensaje especificado.