diff --git a/Makefile b/Makefile index c40dca81..ddd1ad61 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,31 @@ # Sendico Development Environment - Makefile # Docker Compose + Makefile build system -.PHONY: help init build up down restart logs rebuild clean vault-init proto generate generate-api generate-frontend update update-api update-frontend test test-api test-frontend +.PHONY: help init build up down restart logs rebuild clean vault-init proto generate generate-api generate-frontend update update-api update-frontend test test-api test-frontend backend-up backend-down backend-rebuild COMPOSE := docker compose -f docker-compose.dev.yml --env-file .env.dev SERVICE ?= +BACKEND_SERVICES := \ + dev-discovery \ + dev-fx-oracle \ + dev-fx-ingestor \ + dev-billing-fees \ + dev-billing-documents \ + dev-ledger \ + dev-payments-orchestrator \ + dev-payments-quotation \ + dev-payments-methods \ + dev-chain-gateway-vault-agent \ + dev-chain-gateway \ + dev-tron-gateway-vault-agent \ + dev-tron-gateway \ + dev-aurora-gateway \ + dev-tgsettle-gateway \ + dev-notification \ + dev-callbacks-vault-agent \ + dev-callbacks \ + dev-bff-vault-agent \ + dev-bff # Colors GREEN := \033[0;32m @@ -31,6 +52,9 @@ help: @echo "$(YELLOW)Selective Operations:$(NC)" @echo " make infra-up Start infrastructure only (mongo, nats, vault)" @echo " make services-up Start application services only" + @echo " make backend-up Start backend services only (no infrastructure/frontend)" + @echo " make backend-down Stop backend services only" + @echo " make backend-rebuild Rebuild and restart backend services only" @echo " make list-services List all available services" @echo "" @echo "$(YELLOW)Build Groups:$(NC)" @@ -229,6 +253,21 @@ services-up: dev-bff \ dev-frontend +# Backend services only (no infrastructure, no frontend) +backend-up: + @echo "$(GREEN)Starting backend services only (no infra changes)...$(NC)" + @$(COMPOSE) up -d --no-deps $(BACKEND_SERVICES) + +backend-down: + @echo "$(YELLOW)Stopping backend services only...$(NC)" + @$(COMPOSE) stop $(BACKEND_SERVICES) + +backend-rebuild: + @echo "$(GREEN)Rebuilding backend services only (no infra changes)...$(NC)" + @$(COMPOSE) build $(BACKEND_SERVICES) + @$(COMPOSE) up -d --no-deps --force-recreate $(BACKEND_SERVICES) + @echo "$(GREEN)✅ Backend services rebuilt$(NC)" + # Status check status: @$(COMPOSE) ps diff --git a/README.md b/README.md index ba28303f..ad8fc77a 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ Financial services platform providing payment orchestration, ledger accounting, | FX Ingestor | `api/fx/ingestor/` | FX rate ingestion | | Gateway Chain | `api/gateway/chain/` | EVM blockchain gateway | | Gateway TRON | `api/gateway/tron/` | TRON blockchain gateway | +| Gateway Aurora | `api/gateway/aurora/` | Card payouts simulator | | Gateway MNTX | `api/gateway/mntx/` | Card payouts | | Gateway TGSettle | `api/gateway/tgsettle/` | Telegram settlements with MNTX | | Notification | `api/notification/` | Notifications | @@ -31,6 +32,16 @@ Financial services platform providing payment orchestration, ledger accounting, | Callbacks | `api/edge/callbacks/` | Webhook callbacks delivery | | Frontend | `frontend/pweb/` | Flutter web UI | +Gateway note: current dev compose workflows (`make services-up`, `make build-gateways`) use Aurora for card-payout flows (`chain`, `tron`, `aurora`, `tgsettle`). The MNTX gateway codebase is retained separately for Monetix-specific integration. + +## Prerequisites + +- Docker with Docker Compose plugin +- GNU Make +- Go toolchain +- Dart SDK +- Flutter SDK + ## Development Development uses Docker Compose via the Makefile. Run `make help` for all available commands. @@ -54,6 +65,8 @@ make status # Show service status make logs # View all logs make logs SERVICE=dev-ledger # View logs for a specific service make rebuild SERVICE=dev-ledger # Rebuild and restart a specific service +make list-services # List all services and ports +make health # Check service health make clean # Remove all containers and volumes ``` @@ -62,6 +75,7 @@ make clean # Remove all containers and volumes ```bash make infra-up # Start infrastructure only (MongoDB, NATS, Vault) make services-up # Start application services only (assumes infra is running) +make list-services # Show service names, ports, and descriptions ``` ### Build Groups @@ -69,8 +83,8 @@ make services-up # Start application services only (assumes infra is running) ```bash make build-core # discovery, ledger, fees, documents make build-fx # oracle, ingestor -make build-payments # orchestrator -make build-gateways # chain, tron, mntx, tgsettle +make build-payments # orchestrator, quotation, methods +make build-gateways # chain, tron, aurora, tgsettle make build-api # notification, callbacks, bff make build-frontend # Flutter web UI ``` diff --git a/api/edge/bff/interface/api/srequest/payment_intent.go b/api/edge/bff/interface/api/srequest/payment_intent.go index 12b4a52b..86a6929f 100644 --- a/api/edge/bff/interface/api/srequest/payment_intent.go +++ b/api/edge/bff/interface/api/srequest/payment_intent.go @@ -14,6 +14,7 @@ type PaymentIntent struct { SettlementMode SettlementMode `json:"settlement_mode,omitempty"` FeeTreatment FeeTreatment `json:"fee_treatment,omitempty"` Attributes map[string]string `json:"attributes,omitempty"` + Comment string `json:"comment,omitempty"` Customer *Customer `json:"customer,omitempty"` } diff --git a/api/edge/bff/interface/api/sresponse/payment.go b/api/edge/bff/interface/api/sresponse/payment.go index f21dc99c..0ec2559e 100644 --- a/api/edge/bff/interface/api/sresponse/payment.go +++ b/api/edge/bff/interface/api/sresponse/payment.go @@ -70,6 +70,7 @@ type Payment struct { PaymentRef string `json:"paymentRef,omitempty"` IdempotencyKey string `json:"idempotencyKey,omitempty"` State string `json:"state,omitempty"` + Comment string `json:"comment,omitempty"` FailureCode string `json:"failureCode,omitempty"` FailureReason string `json:"failureReason,omitempty"` Operations []PaymentOperation `json:"operations,omitempty"` @@ -294,6 +295,7 @@ func toPayment(p *orchestrationv2.Payment) *Payment { return &Payment{ PaymentRef: p.GetPaymentRef(), State: enumJSONName(p.GetState().String()), + Comment: strings.TrimSpace(p.GetIntentSnapshot().GetComment()), FailureCode: failureCode, FailureReason: failureReason, Operations: operations, diff --git a/api/edge/bff/interface/api/sresponse/payment_test.go b/api/edge/bff/interface/api/sresponse/payment_test.go index 90cf6e32..a2256b81 100644 --- a/api/edge/bff/interface/api/sresponse/payment_test.go +++ b/api/edge/bff/interface/api/sresponse/payment_test.go @@ -121,6 +121,22 @@ func TestToPaymentIgnoresHiddenFailures(t *testing.T) { } } +func TestToPaymentMapsIntentComment(t *testing.T) { + dto := toPayment(&orchestrationv2.Payment{ + PaymentRef: "pay-3", + State: orchestrationv2.OrchestrationState_ORCHESTRATION_STATE_CREATED, + IntentSnapshot: "ationv2.QuoteIntent{ + Comment: " invoice-7 ", + }, + }) + if dto == nil { + t.Fatal("expected non-nil payment dto") + } + if got, want := dto.Comment, "invoice-7"; got != want { + t.Fatalf("comment mismatch: got=%q want=%q", got, want) + } +} + func TestToPaymentQuote_MapsIntentRef(t *testing.T) { dto := toPaymentQuote("ationv2.PaymentQuote{ QuoteRef: "quote-1", diff --git a/api/edge/bff/internal/server/paymentapiimp/mapper.go b/api/edge/bff/internal/server/paymentapiimp/mapper.go index 2a90fbac..4a536888 100644 --- a/api/edge/bff/internal/server/paymentapiimp/mapper.go +++ b/api/edge/bff/internal/server/paymentapiimp/mapper.go @@ -61,9 +61,7 @@ func mapQuoteIntent(intent *srequest.PaymentIntent) (*quotationv2.QuoteIntent, e FeeTreatment: resolvedFeeTreatment, SettlementCurrency: settlementCurrency, Fx: mapFXIntent(intent), - } - if comment := strings.TrimSpace(intent.Attributes["comment"]); comment != "" { - quoteIntent.Comment = comment + Comment: strings.TrimSpace(intent.Comment), } return quoteIntent, nil } diff --git a/api/gateway/aurora/go.mod b/api/gateway/aurora/go.mod index a43cfad8..7c9b1cc4 100644 --- a/api/gateway/aurora/go.mod +++ b/api/gateway/aurora/go.mod @@ -9,7 +9,6 @@ replace github.com/tech/sendico/gateway/common => ../common require ( github.com/go-chi/chi/v5 v5.2.5 github.com/prometheus/client_golang v1.23.2 - github.com/prometheus/client_model v0.6.2 github.com/shopspring/decimal v1.4.0 github.com/tech/sendico/gateway/common v0.1.0 github.com/tech/sendico/pkg v0.1.0 @@ -36,6 +35,7 @@ require ( github.com/nats-io/nats.go v1.49.0 // indirect github.com/nats-io/nkeys v0.4.15 // indirect github.com/nats-io/nuid v1.0.1 // indirect + github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.5 // indirect github.com/prometheus/procfs v0.20.1 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect diff --git a/frontend/pshared/lib/data/dto/payment/intent/payment.dart b/frontend/pshared/lib/data/dto/payment/intent/payment.dart index 7a21d973..9155b16d 100644 --- a/frontend/pshared/lib/data/dto/payment/intent/payment.dart +++ b/frontend/pshared/lib/data/dto/payment/intent/payment.dart @@ -23,6 +23,7 @@ class PaymentIntentDTO { final String? feeTreatment; final Map? attributes; + final String? comment; final CustomerDTO? customer; const PaymentIntentDTO({ @@ -33,10 +34,12 @@ class PaymentIntentDTO { this.fx, this.settlementMode, this.attributes, + this.comment, this.customer, this.feeTreatment, }); - factory PaymentIntentDTO.fromJson(Map json) => _$PaymentIntentDTOFromJson(json); + factory PaymentIntentDTO.fromJson(Map json) => + _$PaymentIntentDTOFromJson(json); Map toJson() => _$PaymentIntentDTOToJson(this); } diff --git a/frontend/pshared/lib/data/mapper/payment/intent/payment.dart b/frontend/pshared/lib/data/mapper/payment/intent/payment.dart index f0a8d00b..7df9494b 100644 --- a/frontend/pshared/lib/data/mapper/payment/intent/payment.dart +++ b/frontend/pshared/lib/data/mapper/payment/intent/payment.dart @@ -16,6 +16,7 @@ extension PaymentIntentMapper on PaymentIntent { fx: fx?.toDTO(), settlementMode: settlementModeToValue(settlementMode), attributes: attributes, + comment: comment, customer: customer?.toDTO(), feeTreatment: feeTreatmentToValue(feeTreatment), ); @@ -30,6 +31,7 @@ extension PaymentIntentDTOMapper on PaymentIntentDTO { fx: fx?.toDomain(), settlementMode: settlementModeFromValue(settlementMode), attributes: attributes, + comment: comment, customer: customer?.toDomain(), feeTreatment: feeTreatmentFromValue(feeTreatment), ); diff --git a/frontend/pshared/lib/models/payment/intent.dart b/frontend/pshared/lib/models/payment/intent.dart index 59cc631f..5fe55a6c 100644 --- a/frontend/pshared/lib/models/payment/intent.dart +++ b/frontend/pshared/lib/models/payment/intent.dart @@ -17,6 +17,7 @@ class PaymentIntent { final FeeTreatment feeTreatment; final SettlementMode settlementMode; final Map? attributes; + final String? comment; final Customer? customer; const PaymentIntent({ @@ -29,6 +30,7 @@ class PaymentIntent { this.fx, this.settlementMode = SettlementMode.unspecified, this.attributes, + this.comment, this.customer, required this.feeTreatment, }); diff --git a/frontend/pshared/test/payment/request_dto_format_test.dart b/frontend/pshared/test/payment/request_dto_format_test.dart index 9cff7713..f584b1d5 100644 --- a/frontend/pshared/test/payment/request_dto_format_test.dart +++ b/frontend/pshared/test/payment/request_dto_format_test.dart @@ -57,6 +57,7 @@ void main() { ), amount: MoneyDTO(amount: '10', currency: 'USD'), settlementMode: 'fix_received', + comment: 'invoice-7', ), ); @@ -70,6 +71,7 @@ void main() { final intent = json['intent'] as Map; expect(intent['kind'], equals('payout')); expect(intent['settlement_mode'], equals('fix_received')); + expect(intent['comment'], equals('invoice-7')); expect(intent.containsKey('settlement_currency'), isFalse); final source = intent['source'] as Map;