Skip to content

Commit 48f1120

Browse files
authored
feat: migrate event proto Money fields to InstrumentAmount (#2115)
* feat: migrate event proto Money fields to InstrumentAmount Replace all google.type.Money fields in financial_accounting_events.proto (8 fields across 4 messages) and current_account_events.proto (10 fields across 5 messages) with meridian.quantity.v1.InstrumentAmount. Changes: - Update CEL validation to string-based regex patterns for amount field - Fix grpc_mappers.go to use toProtoInstrumentAmount for event building - Replace money.Money construction with InstrumentAmount in grpc_control_endpoints.go - Update serialization tests to use InstrumentAmount - Regenerate frontend TypeScript proto files Skip gofumpt hook - it reformats .pb.go imports, causing CI proto freshness check failures. * fix: update serialization test to use InstrumentAmount instead of Money The LedgerPostingCapturedEvent.PostingAmount field was migrated from google.type.Money to quantityv1.InstrumentAmount but this test was not updated, causing a typecheck failure in CI. * fix: use domain instrument version instead of hardcoded 1 in AccountClosedEvent * fix: widen positive-amount CEL regex to accept zero-padded values The previous regex rejected valid positive values like "01" and "0001.50" that the base InstrumentAmount pattern accepts. Use a pattern that checks for any numeric string that is not all-zeros. * chore: regenerate proto files for freshness Commits 700c73b and 736b769 modified proto definitions but the generated .pb.go files were not regenerated. Running buf generate to bring them in sync. * chore: regenerate frontend proto types for event migration * fix: default instrument version to 1 when domain version is 0 Proto validation requires version >= 1. Domain instruments created before versioning was introduced have version 0 as default. --------- Co-authored-by: Ben Coombs <bjcoombs@users.noreply.github.com>
1 parent db0e352 commit 48f1120

10 files changed

Lines changed: 1192 additions & 1250 deletions

File tree

api/proto/meridian/events/v1/current_account_events.pb.go

Lines changed: 558 additions & 534 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/proto/meridian/events/v1/current_account_events.proto

Lines changed: 45 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ package meridian.events.v1;
44

55
import "buf/validate/validate.proto";
66
import "google/protobuf/timestamp.proto";
7-
import "google/type/money.proto";
87
import "meridian/common/v1/types.proto";
8+
import "meridian/quantity/v1/quantity.proto";
99

1010
option go_package = "github.com/meridianhub/meridian/api/proto/meridian/events/v1;eventsv1";
1111

@@ -89,7 +89,7 @@ message AccountCreatedEvent {
8989
}
9090

9191
// AccountStatusChangedEvent represents a status transition for an account
92-
// (e.g., ACTIVE FROZEN, FROZEN ACTIVE, ACTIVE CLOSED).
92+
// (e.g., ACTIVE -> FROZEN, FROZEN -> ACTIVE, ACTIVE -> CLOSED).
9393
// Published when account status changes due to administrative action.
9494
message AccountStatusChangedEvent {
9595
// event_id uniquely identifies this event instance
@@ -277,11 +277,8 @@ message AccountClosedEvent {
277277
pattern: "^[a-zA-Z0-9_-]+$"
278278
}];
279279

280-
// closing_balance is the final balance at closure
281-
// NOTE: buf.validate CEL constraints on google.type.Money don't generate runtime
282-
// validation. Service layer must enforce this constraint.
283-
// See README "Money Field Validation Limitations"
284-
google.type.Money closing_balance = 3 [(buf.validate.field).required = true];
280+
// closing_balance is the final balance at closure (no sign constraint - can be negative)
281+
meridian.quantity.v1.InstrumentAmount closing_balance = 3 [(buf.validate.field).required = true];
285282

286283
// closure_reason explains why the account was closed
287284
string closure_reason = 4 [(buf.validate.field).string = {
@@ -353,16 +350,13 @@ message TransactionInitiatedEvent {
353350
in: ["DEPOSIT", "WITHDRAWAL", "TRANSFER", "FEE", "INTEREST", "ADJUSTMENT"]
354351
}];
355352

356-
// transaction_amount is the amount being transacted
357-
// NOTE: buf.validate CEL constraints on google.type.Money don't generate runtime
358-
// validation. Service layer must enforce this constraint.
359-
// See README "Money Field Validation Limitations"
360-
google.type.Money transaction_amount = 5 [
353+
// transaction_amount is the amount being transacted (must be positive)
354+
meridian.quantity.v1.InstrumentAmount transaction_amount = 5 [
361355
(buf.validate.field).required = true,
362356
(buf.validate.field).cel = {
363357
id: "positive_transaction_amount"
364358
message: "transaction amount must be greater than zero"
365-
expression: "this.units > 0 || (this.units == 0 && this.nanos > 0)"
359+
expression: "this.amount.matches('^[0-9]+(\\\\.[0-9]+)?$') && !this.amount.matches('^0+(\\\\.0+)?$')"
366360
}
367361
];
368362

@@ -451,17 +445,11 @@ message TransactionCompletedEvent {
451445
uuid: true
452446
}];
453447

454-
// new_balance is the account balance after this transaction
455-
// NOTE: buf.validate CEL constraints on google.type.Money don't generate runtime
456-
// validation. Service layer must enforce this constraint.
457-
// See README "Money Field Validation Limitations"
458-
google.type.Money new_balance = 6 [(buf.validate.field).required = true];
448+
// new_balance is the account balance after this transaction (no sign constraint - can be negative for overdraft)
449+
meridian.quantity.v1.InstrumentAmount new_balance = 6 [(buf.validate.field).required = true];
459450

460-
// new_available_balance is the available balance after this transaction
461-
// NOTE: buf.validate CEL constraints on google.type.Money don't generate runtime
462-
// validation. Service layer must enforce this constraint.
463-
// See README "Money Field Validation Limitations"
464-
google.type.Money new_available_balance = 7 [(buf.validate.field).required = true];
451+
// new_available_balance is the available balance after this transaction (no sign constraint - can be negative for overdraft)
452+
meridian.quantity.v1.InstrumentAmount new_available_balance = 7 [(buf.validate.field).required = true];
465453

466454
// completion_reason provides context for completion
467455
string completion_reason = 8 [(buf.validate.field).string = {
@@ -632,14 +620,24 @@ message OverdraftConfiguredEvent {
632620
// overdraft_enabled indicates if overdraft is active
633621
bool overdraft_enabled = 3;
634622

635-
// overdraft_limit is the maximum overdraft amount allowed
636-
// NOTE: buf.validate CEL constraints on google.type.Money don't generate runtime
637-
// validation. Service layer must enforce this constraint.
638-
// See README "Money Field Validation Limitations"
639-
google.type.Money overdraft_limit = 4 [(buf.validate.field).required = true];
623+
// overdraft_limit is the maximum overdraft amount allowed (must be non-negative)
624+
meridian.quantity.v1.InstrumentAmount overdraft_limit = 4 [
625+
(buf.validate.field).required = true,
626+
(buf.validate.field).cel = {
627+
id: "non_negative_overdraft_limit"
628+
message: "overdraft limit must be greater than or equal to zero"
629+
expression: "this.amount.matches('^[0-9]+(\\\\.[0-9]+)?$')"
630+
}
631+
];
640632

641-
// previous_limit is the overdraft limit before this change (optional)
642-
google.type.Money previous_limit = 5;
633+
// previous_limit is the overdraft limit before this change (optional, non-negative)
634+
meridian.quantity.v1.InstrumentAmount previous_limit = 5 [
635+
(buf.validate.field).cel = {
636+
id: "non_negative_previous_limit"
637+
message: "previous limit must be greater than or equal to zero"
638+
expression: "this.amount.matches('^[0-9]+(\\\\.[0-9]+)?$')"
639+
}
640+
];
643641

644642
// interest_rate is the annual interest rate for overdraft (basis points)
645643
int32 interest_rate_basis_points = 6 [(buf.validate.field).int32 = {
@@ -701,35 +699,36 @@ message OverdraftLimitExceededEvent {
701699
uuid: true
702700
}];
703701

704-
// attempted_amount is the amount that was attempted
705-
// NOTE: buf.validate CEL constraints on google.type.Money don't generate runtime
706-
// validation. Service layer must enforce this constraint.
707-
// See README "Money Field Validation Limitations"
708-
google.type.Money attempted_amount = 4 [
702+
// attempted_amount is the amount that was attempted (must be positive)
703+
meridian.quantity.v1.InstrumentAmount attempted_amount = 4 [
709704
(buf.validate.field).required = true,
710705
(buf.validate.field).cel = {
711706
id: "positive_attempted_amount"
712707
message: "attempted amount must be greater than zero"
713-
expression: "this.units > 0 || (this.units == 0 && this.nanos > 0)"
708+
expression: "this.amount.matches('^[0-9]+(\\\\.[0-9]+)?$') && !this.amount.matches('^0+(\\\\.0+)?$')"
714709
}
715710
];
716711

717-
// current_balance is the balance at time of rejection
718-
google.type.Money current_balance = 5 [(buf.validate.field).required = true];
712+
// current_balance is the balance at time of rejection (no sign constraint - can be negative)
713+
meridian.quantity.v1.InstrumentAmount current_balance = 5 [(buf.validate.field).required = true];
719714

720-
// overdraft_limit is the configured overdraft limit
721-
google.type.Money overdraft_limit = 6 [(buf.validate.field).required = true];
715+
// overdraft_limit is the configured overdraft limit (must be non-negative)
716+
meridian.quantity.v1.InstrumentAmount overdraft_limit = 6 [
717+
(buf.validate.field).required = true,
718+
(buf.validate.field).cel = {
719+
id: "non_negative_overdraft_limit"
720+
message: "overdraft limit must be greater than or equal to zero"
721+
expression: "this.amount.matches('^[0-9]+(\\\\.[0-9]+)?$')"
722+
}
723+
];
722724

723-
// shortage is the amount by which the limit was exceeded
724-
// NOTE: buf.validate CEL constraints on google.type.Money don't generate runtime
725-
// validation. Service layer must enforce this constraint.
726-
// See README "Money Field Validation Limitations"
727-
google.type.Money shortage = 7 [
725+
// shortage is the amount by which the limit was exceeded (must be positive)
726+
meridian.quantity.v1.InstrumentAmount shortage = 7 [
728727
(buf.validate.field).required = true,
729728
(buf.validate.field).cel = {
730729
id: "positive_shortage"
731730
message: "shortage must be greater than zero"
732-
expression: "this.units > 0 || (this.units == 0 && this.nanos > 0)"
731+
expression: "this.amount.matches('^[0-9]+(\\\\.[0-9]+)?$') && !this.amount.matches('^0+(\\\\.0+)?$')"
733732
}
734733
];
735734

0 commit comments

Comments
 (0)