Skip to content

ImagLend — Modelo de Datos

Base de Datos

  • Nombre: imagy_lending
  • Usuario: imagy_lending_app (NOBYPASSRLS)
  • RLS: Habilitado en todas las tablas (tenant_id)

Diagrama ER

Tablas

credit_products

Metadata del producto de credito (no contiene la configuracion — esa vive en product_versions).

ColumnaTipoDescripcion
idUUID PKIdentificador unico
tenant_idUUIDTenant propietario (RLS)
codeVARCHAR(50)Codigo unico dentro del tenant
nameVARCHAR(255)Nombre del producto
descriptionTEXTDescripcion
categoryVARCHAR(100)Categoria (microcredito, consumo, linea_rotativa)
is_activeBOOLEANSi esta disponible para nuevas solicitudes
row_versionINTConcurrencia optimista
created_atTIMESTAMPTZFecha de creacion
updated_atTIMESTAMPTZUltima modificacion
created_byUUIDActor que lo creo

Constraint: UNIQUE(tenant_id, code)

product_versions

Versiones inmutables del producto. Cada cambio aprobado crea una nueva version. Las solicitudes referencian la version especifica.

ColumnaTipoDescripcion
idUUID PKIdentificador unico
product_idUUID FKProducto padre
version_numberINTNumero secuencial (1, 2, 3...)
statusVARCHAR(20)active, archived
amount_configJSONBConfiguracion de montos
term_configJSONBConfiguracion de plazos
rate_configJSONBConfiguracion de tasas
fee_configJSONBConfiguracion de fees (array flexible)
requirementsJSONBRequisitos del solicitante
validation_flow_idUUIDFlujo de ImagFlow para validar (nullable)
signature_requiredBOOLEANSi requiere firma
signature_typeVARCHAR(20)digital o electronic
config_snapshotJSONBSnapshot completo de toda la configuracion (redundante para auditoria)
change_request_idUUID FKChange request que origino esta version
change_summaryTEXTResumen del cambio respecto a la version anterior
created_byUUIDQuien solicito el cambio
approved_byUUIDQuien aprobo el cambio
created_atTIMESTAMPTZFecha de creacion
published_atTIMESTAMPTZCuando se activo
archived_atTIMESTAMPTZCuando se archivo (nullable)

Reglas:

  • Solo 1 version active por producto
  • Al publicar nueva version, la anterior pasa a archived
  • Las solicitudes referencian product_version_id, no product_id
  • Una version archivada nunca se modifica

credit_applications

Solicitudes de credito (pre-aprobacion). Cada solicitud referencia la version exacta del producto con la que fue creada.

ColumnaTipoDescripcion
idUUID PKIdentificador unico
tenant_idUUIDTenant (RLS)
organization_idUUIDOrganizacion (nullable)
product_idUUID FKProducto solicitado
product_version_idUUID FKVersion exacta del producto al momento de crear la solicitud
product_config_snapshotJSONBCopia de la configuracion del producto (inmutable)
statusVARCHAR(30)draft, submitted, under_review, approved, rejected, expired
subject_dataJSONBDatos del solicitante (nombre, documento, contacto)
financial_dataJSONBDatos financieros (ingresos, egresos, actividad)
simulation_resultJSONBResultado de la simulacion (monto, plazo, desglose)
originJSONBOrigen de la solicitud (type, channel, flow_id, etc.)
flow_execution_idUUIDID de la ejecucion en ImagFlow (nullable)
signature_idUUIDID de la firma en ImagSign (nullable)
access_tokenVARCHAR(255)Token para wizard publico (nullable)
row_versionINTConcurrencia optimista
created_atTIMESTAMPTZFecha de creacion
expires_atTIMESTAMPTZExpiracion de la solicitud
decided_atTIMESTAMPTZCuando se tomo la decision
decided_byUUIDQuien decidio (nullable si automatico)

credits

Creditos activos (post-aprobacion y desembolso).

ColumnaTipoDescripcion
idUUID PKIdentificador unico
tenant_idUUIDTenant (RLS)
application_idUUID FKSolicitud que lo origino
product_idUUID FKProducto de credito
statusVARCHAR(30)approved, disbursed, active, past_due, defaulted, paid_off
amountDECIMAL(15,2)Monto desembolsado
currencyVARCHAR(3)Moneda (USD, COP, etc.)
term_daysINTPlazo en dias
interest_rateDECIMAL(8,6)Tasa de interes aplicada
fee_breakdownJSONBDesglose de costos aplicados
total_to_payDECIMAL(15,2)Total a pagar (capital + intereses + costos)
originJSONBOrigen (type, channel, flow_request_id)
row_versionINTConcurrencia optimista
created_atTIMESTAMPTZFecha de creacion
disbursed_atTIMESTAMPTZFecha de desembolso
paid_off_atTIMESTAMPTZFecha de pago total (nullable)

disbursements

Registro de desembolsos.

ColumnaTipoDescripcion
idUUID PKIdentificador unico
credit_idUUID FKCredito asociado
tenant_idUUIDTenant (RLS)
amountDECIMAL(15,2)Monto desembolsado
methodVARCHAR(50)bank_transfer, wallet, check
referenceVARCHAR(255)Referencia de la transaccion
statusVARCHAR(20)pending, completed, failed
disbursed_atTIMESTAMPTZFecha efectiva del desembolso
created_atTIMESTAMPTZFecha de registro

payments

Registro de pagos recibidos.

ColumnaTipoDescripcion
idUUID PKIdentificador unico
credit_idUUID FKCredito asociado
tenant_idUUIDTenant (RLS)
amountDECIMAL(15,2)Monto pagado
payment_typeVARCHAR(30)installment, prepayment, partial, penalty
referenceVARCHAR(255)Referencia del pago
statusVARCHAR(20)pending, confirmed, reversed
installment_numberINTNumero de cuota (nullable si prepago)
payment_dateTIMESTAMPTZFecha del pago
created_atTIMESTAMPTZFecha de registro

amortization_schedule

Tabla de amortizacion generada al crear el credito.

ColumnaTipoDescripcion
idUUID PKIdentificador unico
credit_idUUID FKCredito asociado
installment_numberINTNumero de cuota
principalDECIMAL(15,2)Capital de la cuota
interestDECIMAL(15,2)Interes de la cuota
feesDECIMAL(15,2)Costos adicionales
totalDECIMAL(15,2)Total de la cuota
balance_afterDECIMAL(15,2)Saldo despues del pago
due_dateDATEFecha de vencimiento
statusVARCHAR(20)pending, paid, past_due

change_requests

Solicitudes de cambio (maker-checker) para el dominio de lending.

ColumnaTipoDescripcion
idUUID PKIdentificador unico
tenant_idUUIDTenant (RLS)
entity_typeVARCHAR(50)credit_product, credit, configuration
entity_idUUIDID de la entidad a modificar
actionVARCHAR(20)create, update, delete, activate, deactivate
payload_beforeJSONBEstado actual (snapshot)
payload_afterJSONBCambio propuesto
statusVARCHAR(20)pending, approved, rejected, applied, expired
requested_byUUIDQuien solicito
reviewed_byUUIDQuien reviso (nullable)
review_notesTEXTNotas del revisor (nullable)
created_atTIMESTAMPTZFecha de solicitud
reviewed_atTIMESTAMPTZFecha de revision (nullable)
applied_atTIMESTAMPTZFecha de aplicacion (nullable)

Tablas de Soporte

idempotency_keys

Misma estructura que en ImagFlow (ver data-strategy).

processed_events

Misma estructura que en ImagFlow.

RLS Policies

sql
ALTER TABLE credit_products ENABLE ROW LEVEL SECURITY;
ALTER TABLE credit_applications ENABLE ROW LEVEL SECURITY;
ALTER TABLE credits ENABLE ROW LEVEL SECURITY;
ALTER TABLE disbursements ENABLE ROW LEVEL SECURITY;
ALTER TABLE payments ENABLE ROW LEVEL SECURITY;
ALTER TABLE amortization_schedule ENABLE ROW LEVEL SECURITY;
ALTER TABLE change_requests ENABLE ROW LEVEL SECURITY;

-- Todas las tablas usan la misma politica
CREATE POLICY tenant_isolation ON credit_products
    FOR ALL USING (tenant_id = get_current_tenant_id());

-- Control plane para platform admin
CREATE POLICY control_plane ON credit_products
    FOR ALL USING (
        current_setting('app.current_tenant_id', true) IS NULL
        OR current_setting('app.current_tenant_id', true) = ''
    );

Indices

sql
-- Productos
CREATE UNIQUE INDEX idx_credit_products_tenant_code ON credit_products(tenant_id, code);
CREATE INDEX idx_credit_products_active ON credit_products(tenant_id, is_active);

-- Solicitudes
CREATE INDEX idx_applications_tenant_status ON credit_applications(tenant_id, status);
CREATE INDEX idx_applications_token ON credit_applications(access_token);
CREATE INDEX idx_applications_subject ON credit_applications(tenant_id, (subject_data->>'identifier_value'));

-- Creditos
CREATE INDEX idx_credits_tenant_status ON credits(tenant_id, status);
CREATE INDEX idx_credits_application ON credits(application_id);

-- Pagos
CREATE INDEX idx_payments_credit ON payments(credit_id);
CREATE INDEX idx_payments_date ON payments(tenant_id, payment_date DESC);

-- Amortizacion
CREATE INDEX idx_amortization_credit ON amortization_schedule(credit_id, installment_number);
CREATE INDEX idx_amortization_due ON amortization_schedule(due_date) WHERE status = 'pending';

-- Change requests
CREATE INDEX idx_change_requests_tenant_status ON change_requests(tenant_id, status);
CREATE INDEX idx_change_requests_entity ON change_requests(entity_type, entity_id);

Calculos Financieros

Simulacion de Credito

typescript
// Funcion pura — sin efectos secundarios
function calculateCredit(
  amount: number,
  termDays: number,
  product: CreditProductConfig
): SimulationResult {
  const dailyRate = product.rate / 360;
  const interest = amount * dailyRate * termDays;

  // Calcular fees (array flexible)
  const feeBreakdown = product.feeConfig.items.map(fee => ({
    code: fee.code,
    label: fee.label,
    amount: fee.type === 'percentage'
      ? round(amount * fee.value)
      : fee.value,
    taxable: fee.taxable,
  }));

  const totalFees = feeBreakdown.reduce((sum, f) => sum + f.amount, 0);

  // Calcular impuesto segun tax_applies_to
  let taxableBase = 0;
  if (product.feeConfig.tax_applies_to === 'interest') {
    taxableBase = interest;
  } else if (product.feeConfig.tax_applies_to === 'fees') {
    taxableBase = feeBreakdown.filter(f => f.taxable).reduce((sum, f) => sum + f.amount, 0);
  } else { // 'all'
    taxableBase = interest + feeBreakdown.filter(f => f.taxable).reduce((sum, f) => sum + f.amount, 0);
  }
  const tax = round(taxableBase * product.feeConfig.tax_rate);

  const totalToPay = amount + round(interest) + totalFees + tax;

  return {
    amount,
    termDays,
    interest: round(interest),
    feeBreakdown,
    totalFees,
    tax,
    totalToPay,
    monthlyPayment: round(totalToPay / (termDays / 30)),
  };
}

Tabla de Amortizacion

Se genera al momento de crear el credito (post-aprobacion). Metodo: cuota fija (sistema frances) o capital constante (sistema aleman), configurable por producto.

Reimagine Tech LLC — Documentacion Interna