From b457ec86ee14e2e429cd3afdb0f973adb7251612 Mon Sep 17 00:00:00 2001 From: Amir Golmoradi Date: Sun, 27 Sep 2026 16:03:54 +0330 Subject: [PATCH] Define versioned lending event contracts --- docs/events/lending-event-v1.schema.json | 25 +++++++++++++++++++ .../payguard/collateral/v1/collateral.proto | 12 +++++++++ .../main/proto/payguard/loan/v1/loan.proto | 22 ++++++++++++++++ .../java/config/kafka/event/EventTypes.java | 10 ++++++++ .../config/kafka/event/LendingPayload.java | 16 ++++++++++++ .../kafka/topic/PayGuardKafkaTopics.java | 3 +++ 6 files changed, 88 insertions(+) create mode 100644 docs/events/lending-event-v1.schema.json create mode 100644 payguard-shared/src/main/java/config/kafka/event/LendingPayload.java diff --git a/docs/events/lending-event-v1.schema.json b/docs/events/lending-event-v1.schema.json new file mode 100644 index 0000000..9865666 --- /dev/null +++ b/docs/events/lending-event-v1.schema.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://payguard.dev/schema/lending-event-v1.json", + "title": "PayGuard lending event envelope v1", + "type": "object", + "additionalProperties": false, + "required": ["eventId", "eventType", "aggregateType", "aggregateId", "occurredAt", "schemaVersion", "payload"], + "properties": { + "eventId": {"type": "string", "format": "uuid"}, + "eventType": {"type": "string", "enum": ["collateral.locked.v1", "collateral.valuation-updated.v1", "collateral.margin-call.v1", "collateral.liquidated.v1", "collateral.released.v1", "loan.originated.v1", "loan.disbursed.v1", "loan.installment-due.v1", "loan.repaid.v1", "loan.defaulted.v1", "loan.closed.v1"]}, + "aggregateType": {"type": "string", "enum": ["Loan", "Collateral"]}, + "aggregateId": {"type": "string", "minLength": 1}, + "idempotencyKey": {"type": "string"}, + "occurredAt": {"type": "string", "format": "date-time"}, + "producer": {"type": "string"}, + "correlationId": {"type": "string"}, + "causationId": {"type": ["string", "null"]}, + "schemaVersion": {"const": 1}, + "payload": {"$ref": "#/$defs/lendingPayload"} + }, + "$defs": { + "decimal": {"type": "string", "pattern": "^-?[0-9]+(\\.[0-9]+)?$"}, + "lendingPayload": {"type": "object", "additionalProperties": false, "required": ["loanId", "status"], "properties": {"loanId": {"type": "string"}, "collateralId": {"type": ["string", "null"]}, "subjectToken": {"type": ["string", "null"]}, "status": {"type": "string"}, "exposure": {"$ref": "#/$defs/decimal"}, "collateralValue": {"$ref": "#/$defs/decimal"}, "ltv": {"$ref": "#/$defs/decimal"}, "currency": {"type": "string", "pattern": "^[A-Z]{3}$"}, "reason": {"type": ["string", "null"]}, "policyVersion": {"type": ["string", "null"]}}} + } +} diff --git a/payguard-proto/src/main/proto/payguard/collateral/v1/collateral.proto b/payguard-proto/src/main/proto/payguard/collateral/v1/collateral.proto index 334bacf..7ec4729 100644 --- a/payguard-proto/src/main/proto/payguard/collateral/v1/collateral.proto +++ b/payguard-proto/src/main/proto/payguard/collateral/v1/collateral.proto @@ -11,6 +11,8 @@ option java_outer_classname = "CollateralProto"; service CollateralService { rpc GetPosition(GetPositionRequest) returns (CollateralResponse); rpc RefreshPrices(RefreshPricesRequest) returns (RefreshPricesResponse); + rpc LockCollateral(LockCollateralRequest) returns (CollateralResponse); + rpc ReleaseCollateral(GetPositionRequest) returns (CollateralResponse); } message GetPositionRequest { @@ -35,3 +37,13 @@ message RefreshPricesResponse { int32 updated_positions = 1; string status = 2; } + +message LockCollateralRequest { + payguard.common.v1.RequestContext context = 1; + string owner_id = 2; + string loan_id = 3; + payguard.common.v1.Money amount = 4; + string warning_ltv = 5; + string margin_ltv = 6; + string liquidation_ltv = 7; +} diff --git a/payguard-proto/src/main/proto/payguard/loan/v1/loan.proto b/payguard-proto/src/main/proto/payguard/loan/v1/loan.proto index ca0b545..b0908a7 100644 --- a/payguard-proto/src/main/proto/payguard/loan/v1/loan.proto +++ b/payguard-proto/src/main/proto/payguard/loan/v1/loan.proto @@ -12,6 +12,9 @@ service LoanService { rpc GetLoan(GetLoanRequest) returns (LoanResponse); rpc ApproveLoan(LoanCommandRequest) returns (LoanResponse); rpc CreateRepayment(RepaymentRequest) returns (RepaymentResponse); + rpc OriginateLoan(OriginateLoanRequest) returns (LoanResponse); + rpc GetSchedule(GetLoanRequest) returns (ScheduleResponse); + rpc DisputeLoan(LoanCommandRequest) returns (LoanResponse); } message GetLoanRequest { @@ -44,3 +47,22 @@ message RepaymentResponse { string status = 3; payguard.common.v1.Money applied_amount = 4; } + +message OriginateLoanRequest { + payguard.common.v1.RequestContext context = 1; + string borrower_id = 2; + string collateral_id = 3; + payguard.common.v1.Money principal = 4; + string annual_rate = 5; + int32 term_months = 6; +} + +message ScheduleResponse { repeated Installment installments = 1; } +message Installment { + string installment_id = 1; + int32 number = 2; + string due_date = 3; + payguard.common.v1.Money principal = 4; + payguard.common.v1.Money interest = 5; + payguard.common.v1.Money paid = 6; +} diff --git a/payguard-shared/src/main/java/config/kafka/event/EventTypes.java b/payguard-shared/src/main/java/config/kafka/event/EventTypes.java index 4102828..7b4536b 100644 --- a/payguard-shared/src/main/java/config/kafka/event/EventTypes.java +++ b/payguard-shared/src/main/java/config/kafka/event/EventTypes.java @@ -10,6 +10,16 @@ public final class EventTypes { public static final String MARGIN_CALL_TRIGGERED = "MARGIN_CALL_TRIGGERED"; public static final String MARGIN_CALL_RESOLVED = "MARGIN_CALL_RESOLVED"; public static final String LIQUIDATION_TRIGGERED = "LIQUIDATION_TRIGGERED"; + public static final String COLLATERAL_LOCKED = "collateral.locked.v1"; + public static final String COLLATERAL_VALUATION_UPDATED = "collateral.valuation-updated.v1"; + public static final String COLLATERAL_MARGIN_CALL = "collateral.margin-call.v1"; + public static final String COLLATERAL_LIQUIDATED = "collateral.liquidated.v1"; + public static final String COLLATERAL_RELEASED = "collateral.released.v1"; + public static final String LOAN_ORIGINATED = "loan.originated.v1"; + public static final String LOAN_DISBURSED_V1 = "loan.disbursed.v1"; + public static final String LOAN_INSTALLMENT_DUE = "loan.installment-due.v1"; + public static final String LOAN_REPAID = "loan.repaid.v1"; + public static final String LOAN_CLOSED = "loan.closed.v1"; private EventTypes() {} } diff --git a/payguard-shared/src/main/java/config/kafka/event/LendingPayload.java b/payguard-shared/src/main/java/config/kafka/event/LendingPayload.java new file mode 100644 index 0000000..696a550 --- /dev/null +++ b/payguard-shared/src/main/java/config/kafka/event/LendingPayload.java @@ -0,0 +1,16 @@ +package config.kafka.event; + +import java.math.BigDecimal; + +public record LendingPayload( + String loanId, + String collateralId, + String subjectToken, + String status, + BigDecimal exposure, + BigDecimal collateralValue, + BigDecimal ltv, + String currency, + String reason, + String policyVersion) + implements EventPayload {} diff --git a/payguard-shared/src/main/java/config/kafka/topic/PayGuardKafkaTopics.java b/payguard-shared/src/main/java/config/kafka/topic/PayGuardKafkaTopics.java index 47463c0..687ae60 100644 --- a/payguard-shared/src/main/java/config/kafka/topic/PayGuardKafkaTopics.java +++ b/payguard-shared/src/main/java/config/kafka/topic/PayGuardKafkaTopics.java @@ -8,6 +8,9 @@ public final class PayGuardKafkaTopics { public static final String WALLET_TRANSACTIONS_DLT = WALLET_TRANSACTIONS + ".DLT"; public static final String LOAN_LIFECYCLE_DLT = LOAN_LIFECYCLE + ".DLT"; public static final String COLLATERAL_RISK_EVENTS_DLT = COLLATERAL_RISK_EVENTS + ".DLT"; + public static final String LOAN_EVENTS_V1 = "payguard.loan.events.v1"; + public static final String COLLATERAL_EVENTS_V1 = "payguard.collateral.events.v1"; + public static final String WALLET_COMMANDS_V1 = "payguard.wallet.commands.v1"; private PayGuardKafkaTopics() {} }