@fiado/api-invoker 4.76.0 → 4.78.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/index.d.ts +1 -0
- package/bin/index.js +1 -0
- package/bin/loanScoring/api/LoanScoringBusinessApi.d.ts +23 -0
- package/bin/loanScoring/api/LoanScoringBusinessApi.js +47 -0
- package/bin/loanScoring/api/interfaces/ILoanScoringBusinessApi.d.ts +55 -0
- package/bin/loanScoring/api/interfaces/ILoanScoringBusinessApi.js +1 -0
- package/bin/loanScoring/index.d.ts +2 -0
- package/bin/loanScoring/index.js +2 -0
- package/bin/retailCustomer/api/RetailCustomerBusinessApi.d.ts +2 -1
- package/bin/retailCustomer/api/RetailCustomerBusinessApi.js +6 -1
- package/bin/retailCustomer/api/interfaces/IRetailCustomerBusinessApi.d.ts +19 -2
- package/package.json +2 -2
- package/src/index.ts +1 -0
- package/src/loanScoring/api/LoanScoringBusinessApi.ts +45 -0
- package/src/loanScoring/api/interfaces/ILoanScoringBusinessApi.ts +67 -0
- package/src/loanScoring/index.ts +2 -0
- package/src/retailCustomer/api/RetailCustomerBusinessApi.ts +10 -1
- package/src/retailCustomer/api/interfaces/IRetailCustomerBusinessApi.ts +23 -2
package/bin/index.d.ts
CHANGED
|
@@ -86,6 +86,7 @@ export * from "./loanConfig/index.js";
|
|
|
86
86
|
export * from "./loanOfferings/index.js";
|
|
87
87
|
export * from "./loanCollectorAssignment/index.js";
|
|
88
88
|
export * from "./loanCredit/index.js";
|
|
89
|
+
export * from "./loanScoring/index.js";
|
|
89
90
|
export * from "./messages-business/index.js";
|
|
90
91
|
export * from "./totp-security/index.js";
|
|
91
92
|
export * from "./equality-connector/index.js";
|
package/bin/index.js
CHANGED
|
@@ -86,6 +86,7 @@ export * from "./loanConfig/index.js";
|
|
|
86
86
|
export * from "./loanOfferings/index.js";
|
|
87
87
|
export * from "./loanCollectorAssignment/index.js";
|
|
88
88
|
export * from "./loanCredit/index.js";
|
|
89
|
+
export * from "./loanScoring/index.js";
|
|
89
90
|
export * from "./messages-business/index.js";
|
|
90
91
|
export * from "./totp-security/index.js";
|
|
91
92
|
export * from "./equality-connector/index.js";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { IHttpRequest } from "@fiado/http-client";
|
|
2
|
+
import { StandardResponse } from "@fiado/gateway-adapter";
|
|
3
|
+
import { EvaluateSciRequest, EvaluateSciResponse, SciEvaluationResponse } from "@fiado/type-kit/bin/loanScoring/index.js";
|
|
4
|
+
import { ILoanScoringBusinessApi } from "./interfaces/ILoanScoringBusinessApi.js";
|
|
5
|
+
/**
|
|
6
|
+
* Publisher HTTP del lambda `loan-scoring-business` (componente 08 SureKeep Fase 2) para sus 2
|
|
7
|
+
* endpoints privados de scoring. Contrato y semántica completos → `ILoanScoringBusinessApi`
|
|
8
|
+
* (tenantId obligatorio fail-closed, errores por `code`, `StandardResponse` → leer `result.data`).
|
|
9
|
+
*
|
|
10
|
+
* Env var requerida en el consumer: `LOAN_SCORING_BUSINESS_URL`.
|
|
11
|
+
* El template.yml del consumer la setea con:
|
|
12
|
+
*
|
|
13
|
+
* LOAN_SCORING_BUSINESS_URL: '{{resolve:ssm:loan-scoring-business}}'
|
|
14
|
+
*
|
|
15
|
+
* Convención CLAUDE.md global: SSM key = nombre del lambda owner de la URL.
|
|
16
|
+
*/
|
|
17
|
+
export default class LoanScoringBusinessApi implements ILoanScoringBusinessApi {
|
|
18
|
+
private httpRequest;
|
|
19
|
+
private readonly baseUrl;
|
|
20
|
+
constructor(httpRequest: IHttpRequest);
|
|
21
|
+
evaluateScore(request: EvaluateSciRequest, tenantId: string): Promise<StandardResponse<EvaluateSciResponse>>;
|
|
22
|
+
getSciEvaluation(evaluationId: string, tenantId: string): Promise<StandardResponse<SciEvaluationResponse>>;
|
|
23
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
+
};
|
|
13
|
+
import { inject, injectable } from "inversify";
|
|
14
|
+
/**
|
|
15
|
+
* Publisher HTTP del lambda `loan-scoring-business` (componente 08 SureKeep Fase 2) para sus 2
|
|
16
|
+
* endpoints privados de scoring. Contrato y semántica completos → `ILoanScoringBusinessApi`
|
|
17
|
+
* (tenantId obligatorio fail-closed, errores por `code`, `StandardResponse` → leer `result.data`).
|
|
18
|
+
*
|
|
19
|
+
* Env var requerida en el consumer: `LOAN_SCORING_BUSINESS_URL`.
|
|
20
|
+
* El template.yml del consumer la setea con:
|
|
21
|
+
*
|
|
22
|
+
* LOAN_SCORING_BUSINESS_URL: '{{resolve:ssm:loan-scoring-business}}'
|
|
23
|
+
*
|
|
24
|
+
* Convención CLAUDE.md global: SSM key = nombre del lambda owner de la URL.
|
|
25
|
+
*/
|
|
26
|
+
let LoanScoringBusinessApi = class LoanScoringBusinessApi {
|
|
27
|
+
httpRequest;
|
|
28
|
+
// El buildspec publica la URL en SSM con "/" final — se normaliza para no armar "//private".
|
|
29
|
+
baseUrl = (process.env.LOAN_SCORING_BUSINESS_URL || "").replace(/\/+$/, "");
|
|
30
|
+
constructor(httpRequest) {
|
|
31
|
+
this.httpRequest = httpRequest;
|
|
32
|
+
}
|
|
33
|
+
async evaluateScore(request, tenantId) {
|
|
34
|
+
const url = `${this.baseUrl}/private/scoring/evaluate?tenantId=${encodeURIComponent(tenantId)}`;
|
|
35
|
+
return await this.httpRequest.post(url, request);
|
|
36
|
+
}
|
|
37
|
+
async getSciEvaluation(evaluationId, tenantId) {
|
|
38
|
+
const url = `${this.baseUrl}/private/scoring/evaluations/${encodeURIComponent(evaluationId)}?tenantId=${encodeURIComponent(tenantId)}`;
|
|
39
|
+
return await this.httpRequest.get(url);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
LoanScoringBusinessApi = __decorate([
|
|
43
|
+
injectable(),
|
|
44
|
+
__param(0, inject("IHttpRequest")),
|
|
45
|
+
__metadata("design:paramtypes", [Object])
|
|
46
|
+
], LoanScoringBusinessApi);
|
|
47
|
+
export default LoanScoringBusinessApi;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { StandardResponse } from "@fiado/gateway-adapter";
|
|
2
|
+
import { EvaluateSciRequest, EvaluateSciResponse, SciEvaluationResponse } from "@fiado/type-kit/bin/loanScoring/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Contrato del publisher HTTP del lambda `loan-scoring-business` (componente 08 SureKeep Fase 2 —
|
|
5
|
+
* pista Loan/SOFOM) para sus 2 endpoints privados (service-to-service, VPC-only).
|
|
6
|
+
*
|
|
7
|
+
* loan-scoring es el motor del SCI (Score Crediticio Interno, 0-100): evalúa a un acreditado con
|
|
8
|
+
* proveedores intercambiables por configuración (Modelias | Círculo — el consumidor NUNCA sabe
|
|
9
|
+
* cuál corrió), lo traduce a nivel (`BRONZE/SILVER/GOLD`) + decisión, y persiste un snapshot
|
|
10
|
+
* INMUTABLE de cada evaluación. Consumidores previstos:
|
|
11
|
+
* - retail-wizard-business (paso 05 del wizard) → evaluateScore
|
|
12
|
+
* - loan-credit-business (originación) → getSciEvaluation (el `evaluationId` de la
|
|
13
|
+
* respuesta es el `sciAtOrigination` que el crédito referencia)
|
|
14
|
+
*
|
|
15
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
16
|
+
* `tenantId` es OBLIGATORIO en ambos métodos — no es un detalle de firma.
|
|
17
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
18
|
+
* Los privados NO llevan token de usuario (`Feature.ANONIMUS`; la protección es la red VPC),
|
|
19
|
+
* así que el lambda destino no puede inferir el silo. Sin `tenantId` → `400 UNKNOWN_TENANT`
|
|
20
|
+
* (fail-closed). Nunca hay default: sería fail-OPEN cross-SOFOM.
|
|
21
|
+
*
|
|
22
|
+
* ⚠️ Patrón de retorno: `StandardResponse<T>` — el consumer accede `result.data`, NO `result.body`.
|
|
23
|
+
*
|
|
24
|
+
* Errores: el lambda destino lanza `DomainError` tipado → el publisher RECHAZA (no devuelve null).
|
|
25
|
+
* Discriminar por `code` (no por status HTTP):
|
|
26
|
+
* `SCORING_PROVIDER_VALIDATION` (422) — el proveedor rechazó los DATOS del solicitante (CURP/
|
|
27
|
+
* teléfono inválidos). NO reintentar con el mismo payload.
|
|
28
|
+
* `SCORING_PROVIDER_UNAVAILABLE` (502) — proveedor caído/timeout. Transitorio; reintentar es
|
|
29
|
+
* válido (cada retry genera una evaluación/snapshot NUEVOS — el lambda no dedupea).
|
|
30
|
+
* `SCORING_CONFIG_UNAVAILABLE` (502) — loan-config no respondió las perillas del motor.
|
|
31
|
+
* `SCI_EVALUATION_NOT_FOUND` (404) — el evaluationId no existe.
|
|
32
|
+
* `400 UNKNOWN_TENANT` / `400 VALIDATION_ERROR` — tenant ausente/desconocido o body inválido.
|
|
33
|
+
*
|
|
34
|
+
* Env var requerida en el consumer: `LOAN_SCORING_BUSINESS_URL`.
|
|
35
|
+
* El template.yml del consumer la setea con:
|
|
36
|
+
*
|
|
37
|
+
* LOAN_SCORING_BUSINESS_URL: '{{resolve:ssm:loan-scoring-business}}'
|
|
38
|
+
*
|
|
39
|
+
* Convención CLAUDE.md global: SSM key = nombre del lambda owner de la URL.
|
|
40
|
+
*/
|
|
41
|
+
export interface ILoanScoringBusinessApi {
|
|
42
|
+
/**
|
|
43
|
+
* POST /private/scoring/evaluate — evalúa el SCI del acreditado con el proveedor configurado
|
|
44
|
+
* y PERSISTE el snapshot (write crítico: si la respuesta es 200, la evaluación quedó
|
|
45
|
+
* guardada). `antiFraudPassed=false` → decisión REJECTED sin consultar al proveedor.
|
|
46
|
+
*/
|
|
47
|
+
evaluateScore(request: EvaluateSciRequest, tenantId: string): Promise<StandardResponse<EvaluateSciResponse>>;
|
|
48
|
+
/**
|
|
49
|
+
* GET /private/scoring/evaluations/{evaluationId} — lee el snapshot inmutable de una
|
|
50
|
+
* evaluación (con breakdown por capas + auditoría).
|
|
51
|
+
*
|
|
52
|
+
* @throws si la evaluación no existe (`404 SCI_EVALUATION_NOT_FOUND`).
|
|
53
|
+
*/
|
|
54
|
+
getSciEvaluation(evaluationId: string, tenantId: string): Promise<StandardResponse<SciEvaluationResponse>>;
|
|
55
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -3,7 +3,7 @@ import { StandardResponse } from "@fiado/gateway-adapter";
|
|
|
3
3
|
import { UpsertCustomerFromKycRequest, AccountResultRequest, CustomerResponse } from "@fiado/type-kit/bin/retailCustomer/index.js";
|
|
4
4
|
import { IRetailCustomerBusinessApi } from "./interfaces/IRetailCustomerBusinessApi.js";
|
|
5
5
|
/**
|
|
6
|
-
* Publisher HTTP del lambda `retail-customer-business` (SureKeep Fase 2, pista Retail) para sus
|
|
6
|
+
* Publisher HTTP del lambda `retail-customer-business` (SureKeep Fase 2, pista Retail) para sus 5
|
|
7
7
|
* endpoints privados de cliente. Contrato y semántica completos → `IRetailCustomerBusinessApi`.
|
|
8
8
|
*
|
|
9
9
|
* Los paths y el `?tenantId=` matchean `openapi/private.yaml` del lambda destino (mismo patrón que
|
|
@@ -24,4 +24,5 @@ export default class RetailCustomerBusinessApi implements IRetailCustomerBusines
|
|
|
24
24
|
setAccountResult(customerId: string, payload: AccountResultRequest, tenantId: string): Promise<StandardResponse<CustomerResponse>>;
|
|
25
25
|
getCustomerByPhone(phone: string, tenantId: string): Promise<StandardResponse<CustomerResponse>>;
|
|
26
26
|
getCustomer(customerId: string, tenantId: string): Promise<StandardResponse<CustomerResponse>>;
|
|
27
|
+
markWelcomeAccredited(customerId: string, tenantId: string): Promise<StandardResponse<CustomerResponse>>;
|
|
27
28
|
}
|
|
@@ -12,7 +12,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
12
12
|
};
|
|
13
13
|
import { inject, injectable } from "inversify";
|
|
14
14
|
/**
|
|
15
|
-
* Publisher HTTP del lambda `retail-customer-business` (SureKeep Fase 2, pista Retail) para sus
|
|
15
|
+
* Publisher HTTP del lambda `retail-customer-business` (SureKeep Fase 2, pista Retail) para sus 5
|
|
16
16
|
* endpoints privados de cliente. Contrato y semántica completos → `IRetailCustomerBusinessApi`.
|
|
17
17
|
*
|
|
18
18
|
* Los paths y el `?tenantId=` matchean `openapi/private.yaml` del lambda destino (mismo patrón que
|
|
@@ -47,6 +47,11 @@ let RetailCustomerBusinessApi = class RetailCustomerBusinessApi {
|
|
|
47
47
|
const url = `${this.baseUrl}/private/customers/${encodeURIComponent(customerId)}?tenantId=${encodeURIComponent(tenantId)}`;
|
|
48
48
|
return await this.httpRequest.get(url);
|
|
49
49
|
}
|
|
50
|
+
async markWelcomeAccredited(customerId, tenantId) {
|
|
51
|
+
const url = `${this.baseUrl}/private/customers/${encodeURIComponent(customerId)}/welcome-accreditation?tenantId=${encodeURIComponent(tenantId)}`;
|
|
52
|
+
// Sin body: el cliente va en el path y el actor lo pone el destino desde el contexto privado.
|
|
53
|
+
return await this.httpRequest.post(url, {});
|
|
54
|
+
}
|
|
50
55
|
};
|
|
51
56
|
RetailCustomerBusinessApi = __decorate([
|
|
52
57
|
injectable(),
|
|
@@ -2,14 +2,14 @@ import { StandardResponse } from "@fiado/gateway-adapter";
|
|
|
2
2
|
import { UpsertCustomerFromKycRequest, AccountResultRequest, CustomerResponse } from "@fiado/type-kit/bin/retailCustomer/index.js";
|
|
3
3
|
/**
|
|
4
4
|
* Contrato del publisher HTTP del lambda `retail-customer-business` (SureKeep Fase 2, pista Retail)
|
|
5
|
-
* para sus
|
|
5
|
+
* para sus 5 endpoints privados de cliente (service-to-service, VPC-only).
|
|
6
6
|
*
|
|
7
7
|
* Consumidor previsto:
|
|
8
8
|
* - `retail-wizard-business` → upsert del cliente post-KYC, aterrizaje del resultado de apertura
|
|
9
9
|
* de cuenta (D35), y lecturas del cliente por teléfono / id durante la saga de venta.
|
|
10
10
|
*
|
|
11
11
|
* ─────────────────────────────────────────────────────────────────────────────
|
|
12
|
-
* `tenantId` es OBLIGATORIO en los
|
|
12
|
+
* `tenantId` es OBLIGATORIO en los 5 métodos — no es un detalle de firma.
|
|
13
13
|
* ─────────────────────────────────────────────────────────────────────────────
|
|
14
14
|
* Los privados NO llevan token de usuario (`Feature.ANONIMUS`; la protección es la red VPC), así que
|
|
15
15
|
* el lambda destino no tiene `AuthContext.issuer` y NO puede inferir el silo. El caller declara el
|
|
@@ -73,4 +73,21 @@ export interface IRetailCustomerBusinessApi {
|
|
|
73
73
|
* @throws si el cliente no existe (`404 CUSTOMER_NOT_FOUND`).
|
|
74
74
|
*/
|
|
75
75
|
getCustomer(customerId: string, tenantId: string): Promise<StandardResponse<CustomerResponse>>;
|
|
76
|
+
/**
|
|
77
|
+
* POST /private/customers/{customerId}/welcome-accreditation?tenantId= — RESERVA la acreditación
|
|
78
|
+
* del bono de bienvenida (D33). Sin body: el cliente va en el path, el actor lo pone el destino.
|
|
79
|
+
*
|
|
80
|
+
* ⚠️ Reserva, NO acredita. El lambda destino es dueño del flag `welcomeAccredited` y su transición
|
|
81
|
+
* `false → true` es el candado de idempotencia PERMANENTE por cliente (una sola vez para siempre,
|
|
82
|
+
* ni una segunda venta la repite). La condición vive en la transacción DDB, así que dos requests
|
|
83
|
+
* concurrentes NO pueden ganar los dos.
|
|
84
|
+
*
|
|
85
|
+
* Orden obligatorio en el caller: reservar acá PRIMERO, mover plata en el processor DESPUÉS. Al
|
|
86
|
+
* revés, un doble click acredita dos veces plata real.
|
|
87
|
+
*
|
|
88
|
+
* @throws `409 WELCOME_ALREADY_ACCREDITED` si el bono ya se entregó. Para el caller NO es falla:
|
|
89
|
+
* es la señal de "no acredites" — la venta sigue su curso normal.
|
|
90
|
+
* @throws `404 CUSTOMER_NOT_FOUND` si el cliente no existe.
|
|
91
|
+
*/
|
|
92
|
+
markWelcomeAccredited(customerId: string, tenantId: string): Promise<StandardResponse<CustomerResponse>>;
|
|
76
93
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fiado/api-invoker",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.78.0",
|
|
4
4
|
"description": "Sirve como un puente entre diferentes funciones lambda, facilitando la comunicación entre ellas a través de invocaciones http",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "bin/index.js",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"@fiado/gateway-adapter": "^3.9.0",
|
|
35
35
|
"@fiado/http-client": "^2.0.1",
|
|
36
36
|
"@fiado/logger": "^1.1.3",
|
|
37
|
-
"@fiado/type-kit": "^3.
|
|
37
|
+
"@fiado/type-kit": "^3.204.0",
|
|
38
38
|
"dotenv": "^16.4.7"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
package/src/index.ts
CHANGED
|
@@ -86,6 +86,7 @@ export * from "./loanConfig/index.js";
|
|
|
86
86
|
export * from "./loanOfferings/index.js";
|
|
87
87
|
export * from "./loanCollectorAssignment/index.js";
|
|
88
88
|
export * from "./loanCredit/index.js";
|
|
89
|
+
export * from "./loanScoring/index.js";
|
|
89
90
|
export * from "./messages-business/index.js";
|
|
90
91
|
export * from "./totp-security/index.js";
|
|
91
92
|
export * from "./equality-connector/index.js";
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { inject, injectable } from "inversify";
|
|
2
|
+
import type { IHttpRequest } from "@fiado/http-client";
|
|
3
|
+
import { StandardResponse } from "@fiado/gateway-adapter";
|
|
4
|
+
import {
|
|
5
|
+
EvaluateSciRequest,
|
|
6
|
+
EvaluateSciResponse,
|
|
7
|
+
SciEvaluationResponse,
|
|
8
|
+
} from "@fiado/type-kit/bin/loanScoring/index.js";
|
|
9
|
+
import { ILoanScoringBusinessApi } from "./interfaces/ILoanScoringBusinessApi.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Publisher HTTP del lambda `loan-scoring-business` (componente 08 SureKeep Fase 2) para sus 2
|
|
13
|
+
* endpoints privados de scoring. Contrato y semántica completos → `ILoanScoringBusinessApi`
|
|
14
|
+
* (tenantId obligatorio fail-closed, errores por `code`, `StandardResponse` → leer `result.data`).
|
|
15
|
+
*
|
|
16
|
+
* Env var requerida en el consumer: `LOAN_SCORING_BUSINESS_URL`.
|
|
17
|
+
* El template.yml del consumer la setea con:
|
|
18
|
+
*
|
|
19
|
+
* LOAN_SCORING_BUSINESS_URL: '{{resolve:ssm:loan-scoring-business}}'
|
|
20
|
+
*
|
|
21
|
+
* Convención CLAUDE.md global: SSM key = nombre del lambda owner de la URL.
|
|
22
|
+
*/
|
|
23
|
+
@injectable()
|
|
24
|
+
export default class LoanScoringBusinessApi implements ILoanScoringBusinessApi {
|
|
25
|
+
// El buildspec publica la URL en SSM con "/" final — se normaliza para no armar "//private".
|
|
26
|
+
private readonly baseUrl = (process.env.LOAN_SCORING_BUSINESS_URL || "").replace(/\/+$/, "");
|
|
27
|
+
|
|
28
|
+
constructor(@inject("IHttpRequest") private httpRequest: IHttpRequest) {}
|
|
29
|
+
|
|
30
|
+
async evaluateScore(
|
|
31
|
+
request: EvaluateSciRequest,
|
|
32
|
+
tenantId: string,
|
|
33
|
+
): Promise<StandardResponse<EvaluateSciResponse>> {
|
|
34
|
+
const url = `${this.baseUrl}/private/scoring/evaluate?tenantId=${encodeURIComponent(tenantId)}`;
|
|
35
|
+
return await this.httpRequest.post(url, request);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async getSciEvaluation(
|
|
39
|
+
evaluationId: string,
|
|
40
|
+
tenantId: string,
|
|
41
|
+
): Promise<StandardResponse<SciEvaluationResponse>> {
|
|
42
|
+
const url = `${this.baseUrl}/private/scoring/evaluations/${encodeURIComponent(evaluationId)}?tenantId=${encodeURIComponent(tenantId)}`;
|
|
43
|
+
return await this.httpRequest.get(url);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { StandardResponse } from "@fiado/gateway-adapter";
|
|
2
|
+
import {
|
|
3
|
+
EvaluateSciRequest,
|
|
4
|
+
EvaluateSciResponse,
|
|
5
|
+
SciEvaluationResponse,
|
|
6
|
+
} from "@fiado/type-kit/bin/loanScoring/index.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Contrato del publisher HTTP del lambda `loan-scoring-business` (componente 08 SureKeep Fase 2 —
|
|
10
|
+
* pista Loan/SOFOM) para sus 2 endpoints privados (service-to-service, VPC-only).
|
|
11
|
+
*
|
|
12
|
+
* loan-scoring es el motor del SCI (Score Crediticio Interno, 0-100): evalúa a un acreditado con
|
|
13
|
+
* proveedores intercambiables por configuración (Modelias | Círculo — el consumidor NUNCA sabe
|
|
14
|
+
* cuál corrió), lo traduce a nivel (`BRONZE/SILVER/GOLD`) + decisión, y persiste un snapshot
|
|
15
|
+
* INMUTABLE de cada evaluación. Consumidores previstos:
|
|
16
|
+
* - retail-wizard-business (paso 05 del wizard) → evaluateScore
|
|
17
|
+
* - loan-credit-business (originación) → getSciEvaluation (el `evaluationId` de la
|
|
18
|
+
* respuesta es el `sciAtOrigination` que el crédito referencia)
|
|
19
|
+
*
|
|
20
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
21
|
+
* `tenantId` es OBLIGATORIO en ambos métodos — no es un detalle de firma.
|
|
22
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
23
|
+
* Los privados NO llevan token de usuario (`Feature.ANONIMUS`; la protección es la red VPC),
|
|
24
|
+
* así que el lambda destino no puede inferir el silo. Sin `tenantId` → `400 UNKNOWN_TENANT`
|
|
25
|
+
* (fail-closed). Nunca hay default: sería fail-OPEN cross-SOFOM.
|
|
26
|
+
*
|
|
27
|
+
* ⚠️ Patrón de retorno: `StandardResponse<T>` — el consumer accede `result.data`, NO `result.body`.
|
|
28
|
+
*
|
|
29
|
+
* Errores: el lambda destino lanza `DomainError` tipado → el publisher RECHAZA (no devuelve null).
|
|
30
|
+
* Discriminar por `code` (no por status HTTP):
|
|
31
|
+
* `SCORING_PROVIDER_VALIDATION` (422) — el proveedor rechazó los DATOS del solicitante (CURP/
|
|
32
|
+
* teléfono inválidos). NO reintentar con el mismo payload.
|
|
33
|
+
* `SCORING_PROVIDER_UNAVAILABLE` (502) — proveedor caído/timeout. Transitorio; reintentar es
|
|
34
|
+
* válido (cada retry genera una evaluación/snapshot NUEVOS — el lambda no dedupea).
|
|
35
|
+
* `SCORING_CONFIG_UNAVAILABLE` (502) — loan-config no respondió las perillas del motor.
|
|
36
|
+
* `SCI_EVALUATION_NOT_FOUND` (404) — el evaluationId no existe.
|
|
37
|
+
* `400 UNKNOWN_TENANT` / `400 VALIDATION_ERROR` — tenant ausente/desconocido o body inválido.
|
|
38
|
+
*
|
|
39
|
+
* Env var requerida en el consumer: `LOAN_SCORING_BUSINESS_URL`.
|
|
40
|
+
* El template.yml del consumer la setea con:
|
|
41
|
+
*
|
|
42
|
+
* LOAN_SCORING_BUSINESS_URL: '{{resolve:ssm:loan-scoring-business}}'
|
|
43
|
+
*
|
|
44
|
+
* Convención CLAUDE.md global: SSM key = nombre del lambda owner de la URL.
|
|
45
|
+
*/
|
|
46
|
+
export interface ILoanScoringBusinessApi {
|
|
47
|
+
/**
|
|
48
|
+
* POST /private/scoring/evaluate — evalúa el SCI del acreditado con el proveedor configurado
|
|
49
|
+
* y PERSISTE el snapshot (write crítico: si la respuesta es 200, la evaluación quedó
|
|
50
|
+
* guardada). `antiFraudPassed=false` → decisión REJECTED sin consultar al proveedor.
|
|
51
|
+
*/
|
|
52
|
+
evaluateScore(
|
|
53
|
+
request: EvaluateSciRequest,
|
|
54
|
+
tenantId: string,
|
|
55
|
+
): Promise<StandardResponse<EvaluateSciResponse>>;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* GET /private/scoring/evaluations/{evaluationId} — lee el snapshot inmutable de una
|
|
59
|
+
* evaluación (con breakdown por capas + auditoría).
|
|
60
|
+
*
|
|
61
|
+
* @throws si la evaluación no existe (`404 SCI_EVALUATION_NOT_FOUND`).
|
|
62
|
+
*/
|
|
63
|
+
getSciEvaluation(
|
|
64
|
+
evaluationId: string,
|
|
65
|
+
tenantId: string,
|
|
66
|
+
): Promise<StandardResponse<SciEvaluationResponse>>;
|
|
67
|
+
}
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
import { IRetailCustomerBusinessApi } from "./interfaces/IRetailCustomerBusinessApi.js";
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* Publisher HTTP del lambda `retail-customer-business` (SureKeep Fase 2, pista Retail) para sus
|
|
12
|
+
* Publisher HTTP del lambda `retail-customer-business` (SureKeep Fase 2, pista Retail) para sus 5
|
|
13
13
|
* endpoints privados de cliente. Contrato y semántica completos → `IRetailCustomerBusinessApi`.
|
|
14
14
|
*
|
|
15
15
|
* Los paths y el `?tenantId=` matchean `openapi/private.yaml` del lambda destino (mismo patrón que
|
|
@@ -60,4 +60,13 @@ export default class RetailCustomerBusinessApi implements IRetailCustomerBusines
|
|
|
60
60
|
const url = `${this.baseUrl}/private/customers/${encodeURIComponent(customerId)}?tenantId=${encodeURIComponent(tenantId)}`;
|
|
61
61
|
return await this.httpRequest.get(url);
|
|
62
62
|
}
|
|
63
|
+
|
|
64
|
+
async markWelcomeAccredited(
|
|
65
|
+
customerId: string,
|
|
66
|
+
tenantId: string,
|
|
67
|
+
): Promise<StandardResponse<CustomerResponse>> {
|
|
68
|
+
const url = `${this.baseUrl}/private/customers/${encodeURIComponent(customerId)}/welcome-accreditation?tenantId=${encodeURIComponent(tenantId)}`;
|
|
69
|
+
// Sin body: el cliente va en el path y el actor lo pone el destino desde el contexto privado.
|
|
70
|
+
return await this.httpRequest.post(url, {});
|
|
71
|
+
}
|
|
63
72
|
}
|
|
@@ -7,14 +7,14 @@ import {
|
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Contrato del publisher HTTP del lambda `retail-customer-business` (SureKeep Fase 2, pista Retail)
|
|
10
|
-
* para sus
|
|
10
|
+
* para sus 5 endpoints privados de cliente (service-to-service, VPC-only).
|
|
11
11
|
*
|
|
12
12
|
* Consumidor previsto:
|
|
13
13
|
* - `retail-wizard-business` → upsert del cliente post-KYC, aterrizaje del resultado de apertura
|
|
14
14
|
* de cuenta (D35), y lecturas del cliente por teléfono / id durante la saga de venta.
|
|
15
15
|
*
|
|
16
16
|
* ─────────────────────────────────────────────────────────────────────────────
|
|
17
|
-
* `tenantId` es OBLIGATORIO en los
|
|
17
|
+
* `tenantId` es OBLIGATORIO en los 5 métodos — no es un detalle de firma.
|
|
18
18
|
* ─────────────────────────────────────────────────────────────────────────────
|
|
19
19
|
* Los privados NO llevan token de usuario (`Feature.ANONIMUS`; la protección es la red VPC), así que
|
|
20
20
|
* el lambda destino no tiene `AuthContext.issuer` y NO puede inferir el silo. El caller declara el
|
|
@@ -94,4 +94,25 @@ export interface IRetailCustomerBusinessApi {
|
|
|
94
94
|
customerId: string,
|
|
95
95
|
tenantId: string,
|
|
96
96
|
): Promise<StandardResponse<CustomerResponse>>;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* POST /private/customers/{customerId}/welcome-accreditation?tenantId= — RESERVA la acreditación
|
|
100
|
+
* del bono de bienvenida (D33). Sin body: el cliente va en el path, el actor lo pone el destino.
|
|
101
|
+
*
|
|
102
|
+
* ⚠️ Reserva, NO acredita. El lambda destino es dueño del flag `welcomeAccredited` y su transición
|
|
103
|
+
* `false → true` es el candado de idempotencia PERMANENTE por cliente (una sola vez para siempre,
|
|
104
|
+
* ni una segunda venta la repite). La condición vive en la transacción DDB, así que dos requests
|
|
105
|
+
* concurrentes NO pueden ganar los dos.
|
|
106
|
+
*
|
|
107
|
+
* Orden obligatorio en el caller: reservar acá PRIMERO, mover plata en el processor DESPUÉS. Al
|
|
108
|
+
* revés, un doble click acredita dos veces plata real.
|
|
109
|
+
*
|
|
110
|
+
* @throws `409 WELCOME_ALREADY_ACCREDITED` si el bono ya se entregó. Para el caller NO es falla:
|
|
111
|
+
* es la señal de "no acredites" — la venta sigue su curso normal.
|
|
112
|
+
* @throws `404 CUSTOMER_NOT_FOUND` si el cliente no existe.
|
|
113
|
+
*/
|
|
114
|
+
markWelcomeAccredited(
|
|
115
|
+
customerId: string,
|
|
116
|
+
tenantId: string,
|
|
117
|
+
): Promise<StandardResponse<CustomerResponse>>;
|
|
97
118
|
}
|