Billing docs improvement + build opt #696
@@ -1,2 +1,18 @@
|
||||
ci/dev/mongo.key*
|
||||
|
||||
# VCS / editor files
|
||||
.git
|
||||
.vscode
|
||||
.DS_Store
|
||||
**/.DS_Store
|
||||
|
||||
# Local caches and temporary artifacts
|
||||
.cache
|
||||
.gocache
|
||||
**/.gocache
|
||||
**/tmp/
|
||||
**/tmp/**
|
||||
|
||||
# Frontend local build artifacts (rebuilt in Docker)
|
||||
frontend/**/.dart_tool
|
||||
frontend/**/build
|
||||
|
||||
10
Makefile
10
Makefile
@@ -20,7 +20,7 @@ BACKEND_SERVICES := \
|
||||
dev-tron-gateway-vault-agent \
|
||||
dev-tron-gateway \
|
||||
dev-aurora-gateway \
|
||||
dev-tgsettle-gateway \
|
||||
dev-chsettle-gateway \
|
||||
dev-notification \
|
||||
dev-callbacks-vault-agent \
|
||||
dev-callbacks \
|
||||
@@ -61,7 +61,7 @@ help:
|
||||
@echo " make build-core Build core services (discovery, ledger, fees, documents)"
|
||||
@echo " make build-fx Build FX services (oracle, ingestor)"
|
||||
@echo " make build-payments Build payment orchestrator"
|
||||
@echo " make build-gateways Build gateway services (chain, tron, aurora, tgsettle)"
|
||||
@echo " make build-gateways Build gateway services (chain, tron, aurora, chsettle)"
|
||||
@echo " make build-api Build API services (notification, callbacks, bff)"
|
||||
@echo " make build-frontend Build Flutter web frontend"
|
||||
@echo ""
|
||||
@@ -247,7 +247,7 @@ services-up:
|
||||
dev-chain-gateway \
|
||||
dev-tron-gateway \
|
||||
dev-aurora-gateway \
|
||||
dev-tgsettle-gateway \
|
||||
dev-chsettle-gateway \
|
||||
dev-notification \
|
||||
dev-callbacks \
|
||||
dev-bff \
|
||||
@@ -292,7 +292,7 @@ list-services:
|
||||
@echo " - dev-chain-gateway :50070, :9404 (EVM Blockchain Gateway)"
|
||||
@echo " - dev-tron-gateway :50071, :9408 (TRON Blockchain Gateway)"
|
||||
@echo " - dev-aurora-gateway :50075, :9405, :8084 (Card Payouts Simulator)"
|
||||
@echo " - dev-tgsettle-gateway :50080, :9406 (Telegram Settlements)"
|
||||
@echo " - dev-chsettle-gateway :50080, :9406 (Chimera Settlements Simulator)"
|
||||
@echo " - dev-notification :8081 (Notifications)"
|
||||
@echo " - dev-callbacks :9420 (Webhook Callbacks)"
|
||||
@echo " - dev-bff :8080 (Backend for Frontend)"
|
||||
@@ -322,7 +322,7 @@ build-payments:
|
||||
|
||||
build-gateways:
|
||||
@echo "$(GREEN)Building gateway services...$(NC)"
|
||||
@$(COMPOSE) build dev-chain-gateway dev-tron-gateway dev-aurora-gateway dev-tgsettle-gateway
|
||||
@$(COMPOSE) build dev-chain-gateway dev-tron-gateway dev-aurora-gateway dev-chsettle-gateway
|
||||
|
||||
build-api:
|
||||
@echo "$(GREEN)Building API services...$(NC)"
|
||||
|
||||
@@ -25,14 +25,15 @@ Financial services platform providing payment orchestration, ledger accounting,
|
||||
| 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 ChimeraSettle | `api/gateway/chsettle/` | Dummy settlement simulator (fast/slow/success/fail/stuck) |
|
||||
| Gateway MNTX | `api/gateway/mntx/` | Card payouts |
|
||||
| Gateway TGSettle | `api/gateway/tgsettle/` | Telegram settlements with MNTX |
|
||||
| Gateway TGSettle (legacy) | `api/gateway/tgsettle/` | Legacy Telegram settlement gateway (not used in dev compose) |
|
||||
| Notification | `api/notification/` | Notifications |
|
||||
| BFF | `api/edge/bff/` | Backend for frontend |
|
||||
| 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.
|
||||
Gateway note: current dev compose workflows (`make services-up`, `make build-gateways`) use (`chain`, `tron`, `aurora`, `chsettle`). ChimeraSettle is the settlement simulator for test flows; it supports deterministic behavior routing via explicit scenario override and amount buckets. TGSettle remains in-repo as legacy code and is not started by default in dev compose.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
@@ -87,7 +88,7 @@ make list-services # Show service names, ports, and descriptions
|
||||
make build-core # discovery, ledger, fees, documents
|
||||
make build-fx # oracle, ingestor
|
||||
make build-payments # orchestrator, quotation, methods
|
||||
make build-gateways # chain, tron, aurora, tgsettle
|
||||
make build-gateways # chain, tron, aurora, chsettle
|
||||
make build-api # notification, callbacks, bff
|
||||
make build-frontend # Flutter web UI
|
||||
```
|
||||
|
||||
@@ -24,8 +24,6 @@ database:
|
||||
|
||||
documents:
|
||||
issuer:
|
||||
legal_name: "Sendico Ltd"
|
||||
legal_address: "12 Market Street, London, UK"
|
||||
logo_path: "assets/logo.png"
|
||||
templates:
|
||||
acceptance_path: "templates/acceptance.tpl"
|
||||
|
||||
@@ -24,8 +24,6 @@ database:
|
||||
|
||||
documents:
|
||||
issuer:
|
||||
legal_name: "Sendico Ltd"
|
||||
legal_address: "12 Market Street, London, UK"
|
||||
logo_path: "/app/assets/logo.png"
|
||||
templates:
|
||||
acceptance_path: "/app/templates/acceptance.tpl"
|
||||
|
||||
@@ -8,14 +8,14 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.3
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.11
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.11
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.3
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.4
|
||||
github.com/jung-kurt/gofpdf v1.16.2
|
||||
github.com/prometheus/client_golang v1.23.2
|
||||
github.com/shopspring/decimal v1.4.0
|
||||
github.com/tech/sendico/pkg v0.1.0
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||
go.uber.org/zap v1.27.1
|
||||
google.golang.org/grpc v1.79.1
|
||||
google.golang.org/grpc v1.79.2
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
@@ -25,7 +25,7 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.19 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.19 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.20 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.11 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19 // indirect
|
||||
|
||||
@@ -20,8 +20,8 @@ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19 h1:AWeJMk33GTBf6J20XJ
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19/go.mod h1:+GWrYoaAsV7/4pNHpwh1kiNLXkKaSoppxQq9lbH8Ejw=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5 h1:clHU5fm//kWS1C2HgtgWxfQbFbx4b6rx+5jzhgX9HrI=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.19 h1:3Y4oma5TiV7tT9wa8zRcdoXwZkGz9Q/wxbEUK7cMuAM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.19/go.mod h1:V1K+TeJVD5JOk3D9e5tsX2KUdL7BlB+FV6cBhdobN8c=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.20 h1:qi3e/dmpdONhj1RyIZdi6DKKpDXS5Lb8ftr3p7cyHJc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.20/go.mod h1:V1K+TeJVD5JOk3D9e5tsX2KUdL7BlB+FV6cBhdobN8c=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6 h1:XAq62tBTJP/85lFD5oqOOe7YYgWxY9LvWq8plyDvDVg=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.11 h1:BYf7XNsJMzl4mObARUBUib+j2tf0U//JAAtTnYqvqCw=
|
||||
@@ -30,8 +30,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19 h1:X1Tow7su
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19/go.mod h1:/rARO8psX+4sfjUQXp5LLifjUt8DuATZ31WptNJTyQA=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.19 h1:JnQeStZvPHFHeyky/7LbMlyQjUa+jIBj36OlWm0pzIk=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.19/go.mod h1:HGyasyHvYdFQeJhvDHfH7HXkHh57htcJGKDZ+7z+I24=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.3 h1:+d0SsTvxtIJt4tSJ6wr+jrxEMDa6XeupjRv8H7Qitkk=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.3/go.mod h1:ROUNFvFWPwBlOu687WJNQ9cPvd2ccpFrnCiA1YGz50o=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.4 h1:4ExZyubQ6LQQVuF2Qp9OsfEvsTdAWh5Gfwf6PgIdLdk=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.4/go.mod h1:NF3JcMGOiARAss1ld3WGORCw71+4ExDD2cbbdKS5PpA=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.7 h1:Y2cAXlClHsXkkOvWZFXATr34b0hxxloeQu/pAZz2row=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.7/go.mod h1:idzZ7gmDeqeNrSPkdbtMp9qWMgcBwykA7P7Rzh5DXVU=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.12 h1:iSsvB9EtQ09YrsmIc44Heqlx5ByGErqhPK1ZQLppias=
|
||||
@@ -260,8 +260,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
|
||||
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
116
api/billing/documents/internal/content/content.go
Normal file
116
api/billing/documents/internal/content/content.go
Normal file
@@ -0,0 +1,116 @@
|
||||
package content
|
||||
|
||||
// Issuer details are intentionally centralized to avoid document text drift.
|
||||
const (
|
||||
IssuerLegalName = "SMX Operations Limited"
|
||||
IssuerLegalAddress = "Room 607, 12/F., Block C, Hong Kong Industrial Centre, 489-491 Castle Peak Road, Lai Chi Kok, Hong Kong"
|
||||
)
|
||||
|
||||
const (
|
||||
PDFTitleActOfAcceptance = "Act of Acceptance"
|
||||
DocumentIntegrityHashPrefix = "Document integrity hash: "
|
||||
)
|
||||
|
||||
// AcceptanceTemplateContent contains all static copy used by the acceptance act template.
|
||||
type AcceptanceTemplateContent struct {
|
||||
Title string
|
||||
Subtitle string
|
||||
MetaDateLabel string
|
||||
MetaActNumberLabel string
|
||||
SectionParties string
|
||||
PartiesIntro string
|
||||
PartyExecutorLabel string
|
||||
PartyStatusLabel string
|
||||
PartyStatusValue string
|
||||
SectionBasis string
|
||||
BasisLine1 string
|
||||
BasisLine2 string
|
||||
SectionServicesRendered string
|
||||
ServicesRenderedLine1 string
|
||||
ServicesRenderedLine2 string
|
||||
SectionRemuneration string
|
||||
RemunerationHeaderDesc string
|
||||
RemunerationHeaderAmount string
|
||||
RemunerationServicesDesc string
|
||||
SectionConfirmation string
|
||||
ConfirmationLine1 string
|
||||
ConfirmationLine2 string
|
||||
ConfirmationPaymentLine1 string
|
||||
ConfirmationPaymentLine2 string
|
||||
SectionSignatures string
|
||||
SignatureCustomerLine string
|
||||
SignatureExecutorLine string
|
||||
}
|
||||
|
||||
var AcceptanceTemplate = AcceptanceTemplateContent{
|
||||
Title: "ACT OF ACCEPTANCE OF SERVICES",
|
||||
Subtitle: "under the Public Offer Agreement",
|
||||
MetaDateLabel: "Date",
|
||||
MetaActNumberLabel: "Act No",
|
||||
SectionParties: "PARTIES",
|
||||
PartiesIntro: "This Act is made between the following Parties.",
|
||||
PartyExecutorLabel: "Executor",
|
||||
PartyStatusLabel: "Status",
|
||||
PartyStatusValue: "Individual",
|
||||
SectionBasis: "BASIS",
|
||||
BasisLine1: "This Act is issued pursuant to the Public Offer Agreement",
|
||||
BasisLine2: "accepted by the Executor by joining the offer.",
|
||||
SectionServicesRendered: "SERVICES RENDERED",
|
||||
ServicesRenderedLine1: "The Executor has rendered services to the Customer",
|
||||
ServicesRenderedLine2: "in accordance with the terms of the Public Offer Agreement.",
|
||||
SectionRemuneration: "REMUNERATION",
|
||||
RemunerationHeaderDesc: "Description",
|
||||
RemunerationHeaderAmount: "Amount",
|
||||
RemunerationServicesDesc: "Services rendered under the Public Offer Agreement",
|
||||
SectionConfirmation: "CONFIRMATION",
|
||||
ConfirmationLine1: "The Customer confirms that the services were rendered properly",
|
||||
ConfirmationLine2: "and accepted without any claims.",
|
||||
ConfirmationPaymentLine1: "The remuneration for the services was paid to the Executor",
|
||||
ConfirmationPaymentLine2: "using the bank card details provided by the Executor.",
|
||||
SectionSignatures: "SIGNATURES",
|
||||
SignatureCustomerLine: "Customer ___________________________",
|
||||
SignatureExecutorLine: "Executor ___________________________",
|
||||
}
|
||||
|
||||
// OperationDocumentContent contains all static copy for operation documents.
|
||||
type OperationDocumentContent struct {
|
||||
Title string
|
||||
Subtitle string
|
||||
MetaDocumentType string
|
||||
SectionOperation string
|
||||
SectionFailure string
|
||||
RowOrganization string
|
||||
RowGatewayService string
|
||||
RowOperationRef string
|
||||
RowPaymentRef string
|
||||
RowCode string
|
||||
RowState string
|
||||
RowLabel string
|
||||
RowStartedAtUTC string
|
||||
RowCompletedAtUTC string
|
||||
RowAmount string
|
||||
RowFailureCode string
|
||||
RowFailureReason string
|
||||
MissingValuePlaceholder string
|
||||
}
|
||||
|
||||
var OperationDocument = OperationDocumentContent{
|
||||
Title: "OPERATION BILLING DOCUMENT",
|
||||
Subtitle: "Gateway operation statement",
|
||||
MetaDocumentType: "Document Type: Operation",
|
||||
SectionOperation: "OPERATION DETAILS",
|
||||
SectionFailure: "FAILURE DETAILS",
|
||||
RowOrganization: "Organization",
|
||||
RowGatewayService: "Gateway Service",
|
||||
RowOperationRef: "Operation Ref",
|
||||
RowPaymentRef: "Payment Ref",
|
||||
RowCode: "Code",
|
||||
RowState: "State",
|
||||
RowLabel: "Label",
|
||||
RowStartedAtUTC: "Started At (UTC)",
|
||||
RowCompletedAtUTC: "Completed At (UTC)",
|
||||
RowAmount: "Amount",
|
||||
RowFailureCode: "Failure Code",
|
||||
RowFailureReason: "Failure Reason",
|
||||
MissingValuePlaceholder: "n/a",
|
||||
}
|
||||
@@ -3,18 +3,24 @@ package documents
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/tech/sendico/billing/documents/internal/content"
|
||||
"github.com/tech/sendico/billing/documents/internal/docstore"
|
||||
"github.com/tech/sendico/billing/documents/renderer"
|
||||
)
|
||||
|
||||
// Config holds document service settings loaded from YAML.
|
||||
type Config struct {
|
||||
Issuer renderer.Issuer `yaml:"issuer"`
|
||||
Issuer IssuerConfig `yaml:"issuer"`
|
||||
Templates TemplateConfig `yaml:"templates"`
|
||||
Protection ProtectionConfig `yaml:"protection"`
|
||||
Storage docstore.Config `yaml:"storage"`
|
||||
}
|
||||
|
||||
// IssuerConfig defines issuer settings that are environment-specific.
|
||||
type IssuerConfig struct {
|
||||
LogoPath string `yaml:"logo_path"`
|
||||
}
|
||||
|
||||
// TemplateConfig defines document template locations.
|
||||
type TemplateConfig struct {
|
||||
AcceptancePath string `yaml:"acceptance_path"`
|
||||
@@ -25,6 +31,14 @@ type ProtectionConfig struct {
|
||||
OwnerPassword string `yaml:"owner_password"`
|
||||
}
|
||||
|
||||
func (c Config) IssuerDetails() renderer.Issuer {
|
||||
return renderer.Issuer{
|
||||
LegalName: content.IssuerLegalName,
|
||||
LegalAddress: content.IssuerLegalAddress,
|
||||
LogoPath: c.Issuer.LogoPath,
|
||||
}
|
||||
}
|
||||
|
||||
func (c Config) AcceptanceTemplatePath() string {
|
||||
if strings.TrimSpace(c.Templates.AcceptancePath) == "" {
|
||||
return "templates/acceptance.tpl"
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
documentsv1 "github.com/tech/sendico/pkg/proto/billing/documents/v1"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
@@ -17,7 +16,6 @@ var (
|
||||
|
||||
requestsTotal *prometheus.CounterVec
|
||||
requestLatency *prometheus.HistogramVec
|
||||
batchSize prometheus.Histogram
|
||||
documentBytes *prometheus.HistogramVec
|
||||
)
|
||||
|
||||
@@ -44,16 +42,6 @@ func initMetrics() {
|
||||
[]string{"call", "status", "doc_type"},
|
||||
)
|
||||
|
||||
batchSize = promauto.NewHistogram(
|
||||
prometheus.HistogramOpts{
|
||||
Namespace: "billing",
|
||||
Subsystem: "documents",
|
||||
Name: "batch_size",
|
||||
Help: "Number of payment references in batch resolution requests.",
|
||||
Buckets: []float64{0, 1, 2, 5, 10, 20, 50, 100, 250, 500},
|
||||
},
|
||||
)
|
||||
|
||||
documentBytes = promauto.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Namespace: "billing",
|
||||
@@ -67,18 +55,14 @@ func initMetrics() {
|
||||
})
|
||||
}
|
||||
|
||||
func observeRequest(call string, docType documentsv1.DocumentType, statusLabel string, took time.Duration) {
|
||||
typeLabel := docTypeLabel(docType)
|
||||
requestsTotal.WithLabelValues(call, statusLabel, typeLabel).Inc()
|
||||
requestLatency.WithLabelValues(call, statusLabel, typeLabel).Observe(took.Seconds())
|
||||
func observeRequest(call string, documentKind, statusLabel string, took time.Duration) {
|
||||
kind := docKindLabel(documentKind)
|
||||
requestsTotal.WithLabelValues(call, statusLabel, kind).Inc()
|
||||
requestLatency.WithLabelValues(call, statusLabel, kind).Observe(took.Seconds())
|
||||
}
|
||||
|
||||
func observeBatchSize(size int) {
|
||||
batchSize.Observe(float64(size))
|
||||
}
|
||||
|
||||
func observeDocumentBytes(docType documentsv1.DocumentType, size int) {
|
||||
documentBytes.WithLabelValues(docTypeLabel(docType)).Observe(float64(size))
|
||||
func observeDocumentBytes(documentKind string, size int) {
|
||||
documentBytes.WithLabelValues(docKindLabel(documentKind)).Observe(float64(size))
|
||||
}
|
||||
|
||||
func statusFromError(err error) string {
|
||||
@@ -100,10 +84,10 @@ func statusFromError(err error) string {
|
||||
return strings.ToLower(code.String())
|
||||
}
|
||||
|
||||
func docTypeLabel(docType documentsv1.DocumentType) string {
|
||||
label := docType.String()
|
||||
func docKindLabel(documentKind string) string {
|
||||
label := strings.TrimSpace(documentKind)
|
||||
if label == "" {
|
||||
return "DOCUMENT_TYPE_UNSPECIFIED"
|
||||
return "operation"
|
||||
}
|
||||
|
||||
return label
|
||||
|
||||
@@ -5,11 +5,11 @@ import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/tech/sendico/billing/documents/internal/appversion"
|
||||
"github.com/tech/sendico/billing/documents/internal/content"
|
||||
"github.com/tech/sendico/billing/documents/internal/docstore"
|
||||
"github.com/tech/sendico/billing/documents/renderer"
|
||||
"github.com/tech/sendico/billing/documents/storage"
|
||||
@@ -145,94 +145,6 @@ func (s *Service) Shutdown() {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) BatchResolveDocuments(ctx context.Context, req *documentsv1.BatchResolveDocumentsRequest) (resp *documentsv1.BatchResolveDocumentsResponse, err error) {
|
||||
start := time.Now()
|
||||
paymentRefs := 0
|
||||
if req != nil {
|
||||
paymentRefs = len(req.GetPaymentRefs())
|
||||
}
|
||||
|
||||
logger := s.logger.With(zap.Int("payment_refs", paymentRefs))
|
||||
|
||||
defer func() {
|
||||
statusLabel := statusFromError(err)
|
||||
observeRequest("batch_resolve", documentsv1.DocumentType_DOCUMENT_TYPE_UNSPECIFIED, statusLabel, time.Since(start))
|
||||
observeBatchSize(paymentRefs)
|
||||
|
||||
itemsCount := 0
|
||||
if resp != nil {
|
||||
itemsCount = len(resp.GetItems())
|
||||
}
|
||||
|
||||
fields := []zap.Field{
|
||||
zap.String("status", statusLabel),
|
||||
zap.Duration("duration", time.Since(start)),
|
||||
zap.Int("items", itemsCount),
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logger.Warn("BatchResolveDocuments failed", append(fields, zap.Error(err))...)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
logger.Info("BatchResolveDocuments finished", fields...)
|
||||
}()
|
||||
|
||||
_ = ctx
|
||||
err = status.Error(codes.Unimplemented, "payment-level document flow removed; use GetOperationDocument")
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (s *Service) GetDocument(ctx context.Context, req *documentsv1.GetDocumentRequest) (resp *documentsv1.GetDocumentResponse, err error) {
|
||||
start := time.Now()
|
||||
docType := documentsv1.DocumentType_DOCUMENT_TYPE_UNSPECIFIED
|
||||
paymentRef := ""
|
||||
if req != nil {
|
||||
docType = req.GetType()
|
||||
paymentRef = strings.TrimSpace(req.GetPaymentRef())
|
||||
}
|
||||
|
||||
logger := s.logger.With(
|
||||
zap.String("payment_ref", paymentRef),
|
||||
zap.String("document_type", docTypeLabel(docType)),
|
||||
)
|
||||
|
||||
defer func() {
|
||||
statusLabel := statusFromError(err)
|
||||
observeRequest("get_document", docType, statusLabel, time.Since(start))
|
||||
|
||||
if resp != nil {
|
||||
observeDocumentBytes(docType, len(resp.GetContent()))
|
||||
}
|
||||
|
||||
contentBytes := 0
|
||||
if resp != nil {
|
||||
contentBytes = len(resp.GetContent())
|
||||
}
|
||||
|
||||
fields := []zap.Field{
|
||||
zap.String("status", statusLabel),
|
||||
zap.Duration("duration", time.Since(start)),
|
||||
zap.Int("content_bytes", contentBytes),
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logger.Warn("GetDocument failed", append(fields, zap.Error(err))...)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
logger.Info("GetDocument finished", fields...)
|
||||
}()
|
||||
|
||||
_ = ctx
|
||||
err = status.Error(codes.Unimplemented, "payment-level document flow removed; use GetOperationDocument")
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (s *Service) GetOperationDocument(_ context.Context, req *documentsv1.GetOperationDocumentRequest) (resp *documentsv1.GetDocumentResponse, err error) {
|
||||
start := time.Now()
|
||||
organizationRef := ""
|
||||
@@ -253,11 +165,10 @@ func (s *Service) GetOperationDocument(_ context.Context, req *documentsv1.GetOp
|
||||
|
||||
defer func() {
|
||||
statusLabel := statusFromError(err)
|
||||
docType := documentsv1.DocumentType_DOCUMENT_TYPE_UNSPECIFIED
|
||||
observeRequest("get_operation_document", docType, statusLabel, time.Since(start))
|
||||
observeRequest("get_operation_document", "operation", statusLabel, time.Since(start))
|
||||
|
||||
if resp != nil {
|
||||
observeDocumentBytes(docType, len(resp.GetContent()))
|
||||
observeDocumentBytes("operation", len(resp.GetContent()))
|
||||
}
|
||||
|
||||
contentBytes := 0
|
||||
@@ -342,12 +253,6 @@ func (e serviceError) Error() string {
|
||||
return string(e)
|
||||
}
|
||||
|
||||
var (
|
||||
errStorageUnavailable = serviceError("documents: storage not initialised")
|
||||
errDocStoreUnavailable = serviceError("documents: document store not initialised")
|
||||
errTemplateUnavailable = serviceError("documents: template renderer not initialised")
|
||||
)
|
||||
|
||||
func (s *Service) generateActPDF(snapshot model.ActSnapshot) ([]byte, string, error) {
|
||||
blocks, err := s.template.Render(snapshot)
|
||||
if err != nil {
|
||||
@@ -363,7 +268,7 @@ func (s *Service) generateOperationPDF(snapshot operationSnapshot) ([]byte, stri
|
||||
|
||||
func (s *Service) renderPDFWithIntegrity(blocks []renderer.Block) ([]byte, string, error) {
|
||||
generated := renderer.Renderer{
|
||||
Issuer: s.config.Issuer,
|
||||
Issuer: s.config.IssuerDetails(),
|
||||
OwnerPassword: s.config.Protection.OwnerPassword,
|
||||
}
|
||||
|
||||
@@ -427,39 +332,41 @@ func operationSnapshotFromRequest(req *documentsv1.GetOperationDocumentRequest)
|
||||
}
|
||||
|
||||
func buildOperationBlocks(snapshot operationSnapshot) []renderer.Block {
|
||||
documentCopy := content.OperationDocument
|
||||
|
||||
rows := [][]string{
|
||||
{"Organization", snapshot.OrganizationRef},
|
||||
{"Gateway Service", snapshot.GatewayService},
|
||||
{"Operation Ref", snapshot.OperationRef},
|
||||
{"Payment Ref", safeValue(snapshot.PaymentRef)},
|
||||
{"Code", safeValue(snapshot.OperationCode)},
|
||||
{"State", safeValue(snapshot.OperationState)},
|
||||
{"Label", safeValue(snapshot.OperationLabel)},
|
||||
{"Started At (UTC)", formatSnapshotTime(snapshot.StartedAt)},
|
||||
{"Completed At (UTC)", formatSnapshotTime(snapshot.CompletedAt)},
|
||||
{documentCopy.RowOrganization, snapshot.OrganizationRef},
|
||||
{documentCopy.RowGatewayService, snapshot.GatewayService},
|
||||
{documentCopy.RowOperationRef, snapshot.OperationRef},
|
||||
{documentCopy.RowPaymentRef, safeValue(snapshot.PaymentRef)},
|
||||
{documentCopy.RowCode, safeValue(snapshot.OperationCode)},
|
||||
{documentCopy.RowState, safeValue(snapshot.OperationState)},
|
||||
{documentCopy.RowLabel, safeValue(snapshot.OperationLabel)},
|
||||
{documentCopy.RowStartedAtUTC, formatSnapshotTime(snapshot.StartedAt)},
|
||||
{documentCopy.RowCompletedAtUTC, formatSnapshotTime(snapshot.CompletedAt)},
|
||||
}
|
||||
if snapshot.Amount != "" || snapshot.Currency != "" {
|
||||
rows = append(rows, []string{"Amount", strings.TrimSpace(strings.TrimSpace(snapshot.Amount) + " " + strings.TrimSpace(snapshot.Currency))})
|
||||
rows = append(rows, []string{documentCopy.RowAmount, strings.TrimSpace(strings.TrimSpace(snapshot.Amount) + " " + strings.TrimSpace(snapshot.Currency))})
|
||||
}
|
||||
|
||||
blocks := []renderer.Block{
|
||||
{
|
||||
Tag: renderer.TagTitle,
|
||||
Lines: []string{"OPERATION BILLING DOCUMENT"},
|
||||
Lines: []string{documentCopy.Title},
|
||||
},
|
||||
{
|
||||
Tag: renderer.TagSubtitle,
|
||||
Lines: []string{"Gateway operation statement"},
|
||||
Lines: []string{documentCopy.Subtitle},
|
||||
},
|
||||
{
|
||||
Tag: renderer.TagMeta,
|
||||
Lines: []string{
|
||||
"Document Type: Operation",
|
||||
documentCopy.MetaDocumentType,
|
||||
},
|
||||
},
|
||||
{
|
||||
Tag: renderer.TagSection,
|
||||
Lines: []string{"OPERATION DETAILS"},
|
||||
Lines: []string{documentCopy.SectionOperation},
|
||||
},
|
||||
{
|
||||
Tag: renderer.TagKV,
|
||||
@@ -469,12 +376,12 @@ func buildOperationBlocks(snapshot operationSnapshot) []renderer.Block {
|
||||
|
||||
if snapshot.FailureCode != "" || snapshot.FailureReason != "" {
|
||||
blocks = append(blocks,
|
||||
renderer.Block{Tag: renderer.TagSection, Lines: []string{"FAILURE DETAILS"}},
|
||||
renderer.Block{Tag: renderer.TagSection, Lines: []string{documentCopy.SectionFailure}},
|
||||
renderer.Block{
|
||||
Tag: renderer.TagKV,
|
||||
Rows: [][]string{
|
||||
{"Failure Code", safeValue(snapshot.FailureCode)},
|
||||
{"Failure Reason", safeValue(snapshot.FailureReason)},
|
||||
{documentCopy.RowFailureCode, safeValue(snapshot.FailureCode)},
|
||||
{documentCopy.RowFailureReason, safeValue(snapshot.FailureReason)},
|
||||
},
|
||||
},
|
||||
)
|
||||
@@ -485,7 +392,7 @@ func buildOperationBlocks(snapshot operationSnapshot) []renderer.Block {
|
||||
|
||||
func formatSnapshotTime(value time.Time) string {
|
||||
if value.IsZero() {
|
||||
return "n/a"
|
||||
return content.OperationDocument.MissingValuePlaceholder
|
||||
}
|
||||
|
||||
return value.UTC().Format(time.RFC3339)
|
||||
@@ -494,7 +401,7 @@ func formatSnapshotTime(value time.Time) string {
|
||||
func safeValue(value string) string {
|
||||
trimmed := strings.TrimSpace(value)
|
||||
if trimmed == "" {
|
||||
return "n/a"
|
||||
return content.OperationDocument.MissingValuePlaceholder
|
||||
}
|
||||
|
||||
return trimmed
|
||||
@@ -535,50 +442,3 @@ func sanitizeFilenameComponent(value string) string {
|
||||
|
||||
return strings.Trim(b.String(), "_")
|
||||
}
|
||||
|
||||
func toProtoTypes(types []model.DocumentType) []documentsv1.DocumentType {
|
||||
if len(types) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
result := make([]documentsv1.DocumentType, 0, len(types))
|
||||
for _, t := range types {
|
||||
result = append(result, t.Proto())
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func documentStoragePath(paymentRef string, docType documentsv1.DocumentType) string {
|
||||
suffix := "document.pdf"
|
||||
|
||||
switch docType {
|
||||
case documentsv1.DocumentType_DOCUMENT_TYPE_ACT:
|
||||
suffix = "act.pdf"
|
||||
case documentsv1.DocumentType_DOCUMENT_TYPE_INVOICE:
|
||||
suffix = "invoice.pdf"
|
||||
case documentsv1.DocumentType_DOCUMENT_TYPE_RECEIPT:
|
||||
suffix = "receipt.pdf"
|
||||
case documentsv1.DocumentType_DOCUMENT_TYPE_UNSPECIFIED:
|
||||
// default suffix used
|
||||
}
|
||||
|
||||
return filepath.ToSlash(filepath.Join("documents", paymentRef, suffix))
|
||||
}
|
||||
|
||||
func documentFilename(docType documentsv1.DocumentType, paymentRef string) string {
|
||||
name := "document"
|
||||
|
||||
switch docType {
|
||||
case documentsv1.DocumentType_DOCUMENT_TYPE_ACT:
|
||||
name = "act"
|
||||
case documentsv1.DocumentType_DOCUMENT_TYPE_INVOICE:
|
||||
name = "invoice"
|
||||
case documentsv1.DocumentType_DOCUMENT_TYPE_RECEIPT:
|
||||
name = "receipt"
|
||||
case documentsv1.DocumentType_DOCUMENT_TYPE_UNSPECIFIED:
|
||||
// default name used
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s_%s.pdf", name, paymentRef)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/shopspring/decimal"
|
||||
"github.com/tech/sendico/billing/documents/internal/content"
|
||||
"github.com/tech/sendico/billing/documents/renderer"
|
||||
"github.com/tech/sendico/billing/documents/storage"
|
||||
"github.com/tech/sendico/billing/documents/storage/model"
|
||||
@@ -59,10 +60,6 @@ type memDocStore struct {
|
||||
loadCount int
|
||||
}
|
||||
|
||||
func newMemDocStore() *memDocStore {
|
||||
return &memDocStore{data: map[string][]byte{}}
|
||||
}
|
||||
|
||||
func (m *memDocStore) Save(_ context.Context, key string, data []byte) error {
|
||||
m.saveCount++
|
||||
copyData := make([]byte, len(data))
|
||||
@@ -112,15 +109,7 @@ func TestGenerateActPDF_IdempotentAndHashed(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
cfg := Config{
|
||||
Issuer: renderer.Issuer{
|
||||
LegalName: "Sendico Ltd",
|
||||
LegalAddress: "12 Market Street, London, UK",
|
||||
},
|
||||
}
|
||||
|
||||
svc := NewService(zap.NewNop(), nil, nil,
|
||||
WithConfig(cfg),
|
||||
WithTemplateRenderer(tmpl),
|
||||
)
|
||||
|
||||
@@ -164,7 +153,7 @@ func TestGenerateActPDF_IdempotentAndHashed(t *testing.T) {
|
||||
}
|
||||
|
||||
func extractFooterHash(pdf []byte) string {
|
||||
prefix := []byte("Document integrity hash: ")
|
||||
prefix := []byte(content.DocumentIntegrityHashPrefix)
|
||||
idx := bytes.Index(pdf, prefix)
|
||||
|
||||
if idx == -1 {
|
||||
@@ -191,11 +180,7 @@ func isHexDigit(b byte) bool {
|
||||
}
|
||||
|
||||
func TestGetOperationDocument_GeneratesPDF(t *testing.T) {
|
||||
svc := NewService(zap.NewNop(), nil, nil, WithConfig(Config{
|
||||
Issuer: renderer.Issuer{
|
||||
LegalName: "Sendico Ltd",
|
||||
},
|
||||
}))
|
||||
svc := NewService(zap.NewNop(), nil, nil)
|
||||
|
||||
resp, err := svc.GetOperationDocument(context.Background(), &documentsv1.GetOperationDocumentRequest{
|
||||
OrganizationRef: "org-1",
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/shopspring/decimal"
|
||||
"github.com/tech/sendico/billing/documents/internal/content"
|
||||
"github.com/tech/sendico/billing/documents/renderer"
|
||||
"github.com/tech/sendico/billing/documents/storage/model"
|
||||
)
|
||||
@@ -17,6 +18,11 @@ type templateRenderer struct {
|
||||
tpl *template.Template
|
||||
}
|
||||
|
||||
type acceptanceTemplateData struct {
|
||||
model.ActSnapshot
|
||||
Content content.AcceptanceTemplateContent
|
||||
}
|
||||
|
||||
func newTemplateRenderer(path string) (*templateRenderer, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
@@ -38,7 +44,12 @@ func newTemplateRenderer(path string) (*templateRenderer, error) {
|
||||
|
||||
func (r *templateRenderer) Render(snapshot model.ActSnapshot) ([]renderer.Block, error) {
|
||||
var buf bytes.Buffer
|
||||
if err := r.tpl.Execute(&buf, snapshot); err != nil {
|
||||
data := acceptanceTemplateData{
|
||||
ActSnapshot: snapshot,
|
||||
Content: content.AcceptanceTemplate,
|
||||
}
|
||||
|
||||
if err := r.tpl.Execute(&buf, data); err != nil {
|
||||
return nil, fmt.Errorf("execute template: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/shopspring/decimal"
|
||||
"github.com/tech/sendico/billing/documents/internal/content"
|
||||
"github.com/tech/sendico/billing/documents/renderer"
|
||||
"github.com/tech/sendico/billing/documents/storage/model"
|
||||
)
|
||||
@@ -42,7 +43,7 @@ func TestTemplateRenderer_Render(t *testing.T) {
|
||||
t.Fatalf("expected title block")
|
||||
}
|
||||
|
||||
if !slices.Contains(title.Lines, "ACT OF ACCEPTANCE OF SERVICES") {
|
||||
if !slices.Contains(title.Lines, content.AcceptanceTemplate.Title) {
|
||||
t.Fatalf("expected title content not found")
|
||||
}
|
||||
|
||||
@@ -54,7 +55,7 @@ func TestTemplateRenderer_Render(t *testing.T) {
|
||||
foundExecutor := false
|
||||
|
||||
for _, row := range kv.Rows {
|
||||
if len(row) >= 2 && row[0] == "Executor" && row[1] == snapshot.ExecutorFullName {
|
||||
if len(row) >= 2 && row[0] == content.AcceptanceTemplate.PartyExecutorLabel && row[1] == snapshot.ExecutorFullName {
|
||||
foundExecutor = true
|
||||
|
||||
break
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/jung-kurt/gofpdf"
|
||||
"github.com/tech/sendico/billing/documents/internal/content"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -28,7 +29,7 @@ func (r Renderer) Render(blocks []Block, footerHash string) ([]byte, error) {
|
||||
pdf.SetAutoPageBreak(true, pageMarginBottom)
|
||||
pdf.SetCompression(false)
|
||||
pdf.SetAuthor(r.Issuer.LegalName, false)
|
||||
pdf.SetTitle("Act of Acceptance", false)
|
||||
pdf.SetTitle(content.PDFTitleActOfAcceptance, false)
|
||||
|
||||
owner := strings.TrimSpace(r.OwnerPassword)
|
||||
if owner != "" {
|
||||
@@ -39,7 +40,7 @@ func (r Renderer) Render(blocks []Block, footerHash string) ([]byte, error) {
|
||||
pdf.SetY(-15)
|
||||
pdf.SetFont("Helvetica", "", 8)
|
||||
|
||||
footer := "Document integrity hash: " + footerHash
|
||||
footer := content.DocumentIntegrityHashPrefix + footerHash
|
||||
pdf.CellFormat(0, 5, footer, "", 0, "L", false, 0, "")
|
||||
})
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
"unicode/utf16"
|
||||
|
||||
"github.com/tech/sendico/billing/documents/internal/content"
|
||||
)
|
||||
|
||||
func TestRenderer_RenderContainsText(t *testing.T) {
|
||||
@@ -31,7 +33,7 @@ func TestRenderer_RenderContainsText(t *testing.T) {
|
||||
t.Fatalf("expected PDF bytes")
|
||||
}
|
||||
|
||||
checks := []string{"Sendico Ltd", "Jane Doe", "100 USD", "Document integrity hash"}
|
||||
checks := []string{"Sendico Ltd", "Jane Doe", "100 USD", strings.TrimSpace(strings.TrimSuffix(content.DocumentIntegrityHashPrefix, ": "))}
|
||||
|
||||
for _, token := range checks {
|
||||
if !containsPDFText(pdfBytes, token) {
|
||||
|
||||
@@ -6,14 +6,13 @@ import (
|
||||
|
||||
"github.com/shopspring/decimal"
|
||||
"github.com/tech/sendico/pkg/db/storable"
|
||||
documentsv1 "github.com/tech/sendico/pkg/proto/billing/documents/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
DocumentRecordsCollection = "document_records"
|
||||
)
|
||||
|
||||
// DocumentType mirrors the protobuf enum but stores string names for Mongo compatibility.
|
||||
// DocumentType represents document kinds cached in storage.
|
||||
type DocumentType string
|
||||
|
||||
const (
|
||||
@@ -23,24 +22,6 @@ const (
|
||||
DocumentTypeReceipt DocumentType = "DOCUMENT_TYPE_RECEIPT"
|
||||
)
|
||||
|
||||
// DocumentTypeFromProto converts a protobuf enum to the storage representation.
|
||||
func DocumentTypeFromProto(t documentsv1.DocumentType) DocumentType {
|
||||
if name, ok := documentsv1.DocumentType_name[int32(t)]; ok {
|
||||
return DocumentType(name)
|
||||
}
|
||||
|
||||
return DocumentTypeUnspecified
|
||||
}
|
||||
|
||||
// Proto converts the storage representation to a protobuf enum.
|
||||
func (t DocumentType) Proto() documentsv1.DocumentType {
|
||||
if value, ok := documentsv1.DocumentType_value[string(t)]; ok {
|
||||
return documentsv1.DocumentType(value)
|
||||
}
|
||||
|
||||
return documentsv1.DocumentType_DOCUMENT_TYPE_UNSPECIFIED
|
||||
}
|
||||
|
||||
// ActSnapshot captures the immutable data needed to generate an acceptance act.
|
||||
type ActSnapshot struct {
|
||||
PaymentID string `bson:"paymentId" json:"paymentId"`
|
||||
|
||||
@@ -2,66 +2,66 @@
|
||||
|
||||
|
||||
#title
|
||||
ACT OF ACCEPTANCE OF SERVICES
|
||||
{{ .Content.Title }}
|
||||
|
||||
#subtitle
|
||||
under the Public Offer Agreement
|
||||
{{ .Content.Subtitle }}
|
||||
|
||||
#meta
|
||||
Date: {{ date .Date }}
|
||||
Act No: {{ .PaymentID }}
|
||||
{{ .Content.MetaDateLabel }}: {{ date .Date }}
|
||||
{{ .Content.MetaActNumberLabel }}: {{ .PaymentID }}
|
||||
|
||||
|
||||
#section
|
||||
PARTIES
|
||||
{{ .Content.SectionParties }}
|
||||
|
||||
#text
|
||||
This Act is made between the following Parties.
|
||||
{{ .Content.PartiesIntro }}
|
||||
|
||||
#kv
|
||||
Executor | {{ .ExecutorFullName }}
|
||||
Status | Individual
|
||||
{{ .Content.PartyExecutorLabel }} | {{ .ExecutorFullName }}
|
||||
{{ .Content.PartyStatusLabel }} | {{ .Content.PartyStatusValue }}
|
||||
|
||||
|
||||
#section
|
||||
BASIS
|
||||
{{ .Content.SectionBasis }}
|
||||
|
||||
#text
|
||||
This Act is issued pursuant to the Public Offer Agreement
|
||||
accepted by the Executor by joining the offer.
|
||||
{{ .Content.BasisLine1 }}
|
||||
{{ .Content.BasisLine2 }}
|
||||
|
||||
|
||||
#section
|
||||
SERVICES RENDERED
|
||||
{{ .Content.SectionServicesRendered }}
|
||||
|
||||
#text
|
||||
The Executor has rendered services to the Customer
|
||||
in accordance with the terms of the Public Offer Agreement.
|
||||
{{ .Content.ServicesRenderedLine1 }}
|
||||
{{ .Content.ServicesRenderedLine2 }}
|
||||
|
||||
|
||||
#section
|
||||
REMUNERATION
|
||||
{{ .Content.SectionRemuneration }}
|
||||
|
||||
#table
|
||||
Description | Amount
|
||||
Services rendered under the Public Offer Agreement | {{ money .Amount .Currency }}
|
||||
{{ .Content.RemunerationHeaderDesc }} | {{ .Content.RemunerationHeaderAmount }}
|
||||
{{ .Content.RemunerationServicesDesc }} | {{ money .Amount .Currency }}
|
||||
|
||||
|
||||
#section
|
||||
CONFIRMATION
|
||||
{{ .Content.SectionConfirmation }}
|
||||
|
||||
#text
|
||||
The Customer confirms that the services were rendered properly
|
||||
and accepted without any claims.
|
||||
{{ .Content.ConfirmationLine1 }}
|
||||
{{ .Content.ConfirmationLine2 }}
|
||||
|
||||
The remuneration for the services was paid to the Executor
|
||||
using the bank card details provided by the Executor.
|
||||
{{ .Content.ConfirmationPaymentLine1 }}
|
||||
{{ .Content.ConfirmationPaymentLine2 }}
|
||||
|
||||
|
||||
#section
|
||||
SIGNATURES
|
||||
{{ .Content.SectionSignatures }}
|
||||
|
||||
#sign
|
||||
Customer ___________________________
|
||||
{{ .Content.SignatureCustomerLine }}
|
||||
|
||||
Executor ___________________________
|
||||
{{ .Content.SignatureExecutorLine }}
|
||||
|
||||
@@ -10,7 +10,7 @@ require (
|
||||
github.com/tech/sendico/fx/oracle v0.0.0
|
||||
github.com/tech/sendico/pkg v0.1.0
|
||||
go.uber.org/zap v1.27.1
|
||||
google.golang.org/grpc v1.79.1
|
||||
google.golang.org/grpc v1.79.2
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
|
||||
@@ -210,8 +210,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
|
||||
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -44,6 +44,6 @@ require (
|
||||
golang.org/x/sys v0.41.0 // indirect
|
||||
golang.org/x/text v0.34.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
|
||||
google.golang.org/grpc v1.79.1 // indirect
|
||||
google.golang.org/grpc v1.79.2 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
)
|
||||
|
||||
@@ -210,8 +210,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
|
||||
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -18,7 +18,7 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.3
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.11
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.11
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.3
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.4
|
||||
github.com/go-chi/chi/v5 v5.2.5
|
||||
github.com/go-chi/cors v1.2.2
|
||||
github.com/go-chi/jwtauth/v5 v5.4.0
|
||||
@@ -38,7 +38,7 @@ require (
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||
go.uber.org/zap v1.27.1
|
||||
golang.org/x/net v0.51.0
|
||||
google.golang.org/grpc v1.79.1
|
||||
google.golang.org/grpc v1.79.2
|
||||
google.golang.org/protobuf v1.36.11
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
moul.io/chizap v1.0.3
|
||||
@@ -59,7 +59,7 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.19 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.19 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.20 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.11 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19 // indirect
|
||||
|
||||
@@ -22,8 +22,8 @@ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19 h1:AWeJMk33GTBf6J20XJ
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19/go.mod h1:+GWrYoaAsV7/4pNHpwh1kiNLXkKaSoppxQq9lbH8Ejw=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5 h1:clHU5fm//kWS1C2HgtgWxfQbFbx4b6rx+5jzhgX9HrI=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.19 h1:3Y4oma5TiV7tT9wa8zRcdoXwZkGz9Q/wxbEUK7cMuAM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.19/go.mod h1:V1K+TeJVD5JOk3D9e5tsX2KUdL7BlB+FV6cBhdobN8c=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.20 h1:qi3e/dmpdONhj1RyIZdi6DKKpDXS5Lb8ftr3p7cyHJc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.20/go.mod h1:V1K+TeJVD5JOk3D9e5tsX2KUdL7BlB+FV6cBhdobN8c=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6 h1:XAq62tBTJP/85lFD5oqOOe7YYgWxY9LvWq8plyDvDVg=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.11 h1:BYf7XNsJMzl4mObARUBUib+j2tf0U//JAAtTnYqvqCw=
|
||||
@@ -32,8 +32,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19 h1:X1Tow7su
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19/go.mod h1:/rARO8psX+4sfjUQXp5LLifjUt8DuATZ31WptNJTyQA=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.19 h1:JnQeStZvPHFHeyky/7LbMlyQjUa+jIBj36OlWm0pzIk=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.19/go.mod h1:HGyasyHvYdFQeJhvDHfH7HXkHh57htcJGKDZ+7z+I24=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.3 h1:+d0SsTvxtIJt4tSJ6wr+jrxEMDa6XeupjRv8H7Qitkk=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.3/go.mod h1:ROUNFvFWPwBlOu687WJNQ9cPvd2ccpFrnCiA1YGz50o=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.4 h1:4ExZyubQ6LQQVuF2Qp9OsfEvsTdAWh5Gfwf6PgIdLdk=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.4/go.mod h1:NF3JcMGOiARAss1ld3WGORCw71+4ExDD2cbbdKS5PpA=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.7 h1:Y2cAXlClHsXkkOvWZFXATr34b0hxxloeQu/pAZz2row=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.7/go.mod h1:idzZ7gmDeqeNrSPkdbtMp9qWMgcBwykA7P7Rzh5DXVU=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.12 h1:iSsvB9EtQ09YrsmIc44Heqlx5ByGErqhPK1ZQLppias=
|
||||
@@ -403,8 +403,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 h1:
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171/go.mod h1:M5krXqk4GhBKvB596udGL3UyjL4I1+cTbK0orROM9ng=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
|
||||
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -59,6 +59,6 @@ require (
|
||||
golang.org/x/text v0.34.0 // indirect
|
||||
golang.org/x/time v0.14.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
|
||||
google.golang.org/grpc v1.79.1 // indirect
|
||||
google.golang.org/grpc v1.79.2 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
)
|
||||
|
||||
@@ -245,8 +245,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
|
||||
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -48,6 +48,6 @@ require (
|
||||
golang.org/x/sys v0.41.0 // indirect
|
||||
golang.org/x/text v0.34.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
|
||||
google.golang.org/grpc v1.79.1 // indirect
|
||||
google.golang.org/grpc v1.79.2 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
)
|
||||
|
||||
@@ -210,8 +210,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
|
||||
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -13,7 +13,7 @@ require (
|
||||
github.com/tech/sendico/pkg v0.1.0
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||
go.uber.org/zap v1.27.1
|
||||
google.golang.org/grpc v1.79.1
|
||||
google.golang.org/grpc v1.79.2
|
||||
google.golang.org/protobuf v1.36.11
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
@@ -210,8 +210,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
|
||||
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
101
api/gateway/chsettle/README.md
Normal file
101
api/gateway/chsettle/README.md
Normal file
@@ -0,0 +1,101 @@
|
||||
# ChimeraSettle Gateway (`chsettle`)
|
||||
|
||||
ChimeraSettle is a dummy settlement gateway for dev/test flows.
|
||||
It simulates settlement outcomes deterministically, without real fund movement.
|
||||
|
||||
## What It Simulates
|
||||
|
||||
- Fast success
|
||||
- Slow success
|
||||
- Immediate failure
|
||||
- Timeout-like failure
|
||||
- Stuck pending/processing
|
||||
- Retry-like progression before success
|
||||
- Deterministic chaos bucket
|
||||
|
||||
## How Behavior Is Chosen
|
||||
|
||||
Selection order:
|
||||
|
||||
1. Explicit scenario override from request metadata:
|
||||
- `chsettle_scenario`
|
||||
- `scenario` (alias)
|
||||
|
||||
2. Amount bucket routing based on:
|
||||
- `amount_minor % 1000`
|
||||
|
||||
3. Hash fallback using idempotency key (if amount cannot be parsed)
|
||||
|
||||
## Scenario Overrides
|
||||
|
||||
Accepted override values (aliases supported in code):
|
||||
|
||||
- `fast_success`
|
||||
- `slow_success`
|
||||
- `fail_immediate`
|
||||
- `fail_timeout`
|
||||
- `stuck_pending` (also `stuck`)
|
||||
- `retry_then_success`
|
||||
- `webhook_delayed_success`
|
||||
- `slow_then_fail`
|
||||
- `partial_progress_stuck`
|
||||
- `chaos`
|
||||
|
||||
## Amount Bucket Map (`%1000`)
|
||||
|
||||
| Slot range | Scenario |
|
||||
|---|---|
|
||||
| `000-099` | `fast_success` |
|
||||
| `100-199` | `slow_success` |
|
||||
| `200-299` | `fail_immediate` |
|
||||
| `300-399` | `fail_timeout` |
|
||||
| `400-499` | `stuck_pending` |
|
||||
| `500-599` | `retry_then_success` |
|
||||
| `600-699` | `webhook_delayed_success` |
|
||||
| `700-799` | `slow_then_fail` |
|
||||
| `800-899` | `partial_progress_stuck` |
|
||||
| `900-999` | `chaos` (deterministic by idempotency key) |
|
||||
|
||||
## Request Usage
|
||||
|
||||
### Through Connector `SubmitOperation`
|
||||
|
||||
Use operation param:
|
||||
|
||||
- `scenario` (optional)
|
||||
|
||||
or put it inside `metadata` as:
|
||||
|
||||
- `chsettle_scenario`
|
||||
|
||||
### Through Gateway `SubmitTransfer`
|
||||
|
||||
Set metadata key directly:
|
||||
|
||||
- `chsettle_scenario`
|
||||
|
||||
## Dev Environment
|
||||
|
||||
Compose service:
|
||||
|
||||
- `dev-chsettle-gateway`
|
||||
|
||||
Ports:
|
||||
|
||||
- gRPC: `50080`
|
||||
- metrics: `9406`
|
||||
|
||||
Start only this gateway:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.dev.yml --env-file .env.dev up -d dev-chsettle-gateway
|
||||
```
|
||||
|
||||
## Logging
|
||||
|
||||
ChimeraSettle emits:
|
||||
|
||||
- `info` logs for scenario decisions and transition milestones
|
||||
- `warn` logs for recoverable/non-fatal errors
|
||||
- `error` logs for startup-fatal failures
|
||||
- detailed `debug` logs for request execution tracing
|
||||
@@ -11,7 +11,7 @@ require (
|
||||
github.com/tech/sendico/pkg v0.1.0
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||
go.uber.org/zap v1.27.1
|
||||
google.golang.org/grpc v1.79.1
|
||||
google.golang.org/grpc v1.79.2
|
||||
google.golang.org/protobuf v1.36.11
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
@@ -212,8 +212,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
|
||||
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -51,6 +51,6 @@ require (
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/sys v0.41.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
|
||||
google.golang.org/grpc v1.79.1 // indirect
|
||||
google.golang.org/grpc v1.79.2 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
)
|
||||
|
||||
@@ -227,8 +227,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
|
||||
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -11,7 +11,7 @@ require (
|
||||
github.com/tech/sendico/pkg v0.1.0
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||
go.uber.org/zap v1.27.1
|
||||
google.golang.org/grpc v1.79.1
|
||||
google.golang.org/grpc v1.79.2
|
||||
google.golang.org/protobuf v1.36.11
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
@@ -212,8 +212,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
|
||||
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -25,7 +25,7 @@ require (
|
||||
github.com/tech/sendico/pkg v0.1.0
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||
go.uber.org/zap v1.27.1
|
||||
google.golang.org/grpc v1.79.1
|
||||
google.golang.org/grpc v1.79.2
|
||||
google.golang.org/protobuf v1.36.11
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
@@ -213,8 +213,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
|
||||
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -19,7 +19,7 @@ require (
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||
go.uber.org/zap v1.27.1
|
||||
golang.org/x/crypto v0.48.0
|
||||
google.golang.org/grpc v1.79.1
|
||||
google.golang.org/grpc v1.79.2
|
||||
google.golang.org/protobuf v1.36.11
|
||||
)
|
||||
|
||||
|
||||
@@ -344,8 +344,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b h1:
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:Xa7le7qx2vmqB/SzWUBa7KdMjpdpAHlh5QCSnjessQk=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
|
||||
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -39,6 +39,7 @@ const (
|
||||
ChainTransfers Type = "chain_transfers" // Represents chain transfers
|
||||
ChainDeposits Type = "chain_deposits" // Represents chain deposits
|
||||
Callbacks Type = "callbacks" // Represents webhook callback subscriptions
|
||||
ChSettle Type = "chsettle_gateway" // Represents chimera settlement gateway
|
||||
Notifications Type = "notifications" // Represents notifications sent to users
|
||||
Organizations Type = "organizations" // Represents organizations in the system
|
||||
Payments Type = "payments" // Represents payments service
|
||||
@@ -66,7 +67,7 @@ func StringToSType(s string) (Type, error) {
|
||||
ChainTransfers, ChainDeposits, Callbacks, MntxGateway, PaymentGateway, FXOracle, FeePlans, BillingDocuments, FilterProjects, Invitations, Invoices, Logo, Ledger,
|
||||
LedgerAccounts, LedgerBalances, LedgerEntries, LedgerOutbox, LedgerParties, LedgerPlines, Notifications,
|
||||
Organizations, Payments, PaymentRoutes, PaymentOrchestrator, PaymentMethods, Permissions, Policies, PolicyAssignements,
|
||||
Recipients, RefreshTokens, Roles, Storage, Tenants, Workflows, Discovery:
|
||||
Recipients, RefreshTokens, Roles, Storage, Tenants, Workflows, Discovery, ChSettle:
|
||||
return Type(s), nil
|
||||
default:
|
||||
return "", merrors.InvalidArgument("invalid service type", s)
|
||||
|
||||
@@ -5,94 +5,18 @@ package billing.documents.v1;
|
||||
option go_package = "github.com/tech/sendico/pkg/proto/billing/documents/v1;documentsv1";
|
||||
|
||||
|
||||
// ---------------------------
|
||||
// ENUMS
|
||||
// ---------------------------
|
||||
|
||||
// DocumentType defines supported accounting document kinds.
|
||||
enum DocumentType {
|
||||
DOCUMENT_TYPE_UNSPECIFIED = 0;
|
||||
|
||||
// Invoice issued for the payment
|
||||
DOCUMENT_TYPE_INVOICE = 1;
|
||||
|
||||
// Service acceptance act (common in EU/RU accounting)
|
||||
DOCUMENT_TYPE_ACT = 2;
|
||||
|
||||
// Simple receipt confirmation
|
||||
DOCUMENT_TYPE_RECEIPT = 3;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------
|
||||
// SERVICE
|
||||
// ---------------------------
|
||||
|
||||
// DocumentService provides document metadata for payment lists
|
||||
// and lazy document generation on demand.
|
||||
// DocumentService provides operation-level document generation.
|
||||
service DocumentService {
|
||||
|
||||
// BatchResolveDocuments is used by BFF when rendering
|
||||
// a page of payments. This prevents N+1 calls by resolving
|
||||
// document metadata for many payments in a single request.
|
||||
rpc BatchResolveDocuments(BatchResolveDocumentsRequest)
|
||||
returns (BatchResolveDocumentsResponse);
|
||||
|
||||
// GetDocument returns the actual PDF file.
|
||||
// If the document was not generated before, the service
|
||||
// generates it lazily, stores it, and returns it.
|
||||
rpc GetDocument(GetDocumentRequest)
|
||||
returns (GetDocumentResponse);
|
||||
|
||||
// GetOperationDocument returns a generated PDF file for
|
||||
// a gateway operation snapshot provided by the caller.
|
||||
rpc GetOperationDocument(GetOperationDocumentRequest)
|
||||
returns (GetDocumentResponse);
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------
|
||||
// BATCH RESOLVE (for payment tables)
|
||||
// ---------------------------
|
||||
|
||||
// BatchResolveDocumentsRequest contains a list of payment references
|
||||
// for which document availability should be resolved.
|
||||
message BatchResolveDocumentsRequest {
|
||||
repeated string payment_refs = 1;
|
||||
}
|
||||
|
||||
// DocumentMeta describes document availability for a single payment.
|
||||
message DocumentMeta {
|
||||
// Payment reference
|
||||
string payment_ref = 1;
|
||||
|
||||
// Document types that are applicable for this payment
|
||||
// based on business rules and payment snapshot.
|
||||
repeated DocumentType available_types = 2;
|
||||
|
||||
// Document types that were already generated and stored.
|
||||
// Other available types will be generated lazily when requested.
|
||||
repeated DocumentType ready_types = 3;
|
||||
}
|
||||
|
||||
// BatchResolveDocumentsResponse returns metadata for all requested payments.
|
||||
message BatchResolveDocumentsResponse {
|
||||
repeated DocumentMeta items = 1;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------
|
||||
// GET DOCUMENT (lazy generation)
|
||||
// ---------------------------
|
||||
|
||||
// GetDocumentRequest requests a specific document for a payment.
|
||||
message GetDocumentRequest {
|
||||
string payment_ref = 1;
|
||||
|
||||
// Type of document to retrieve (invoice, act, receipt, etc.)
|
||||
DocumentType type = 2;
|
||||
}
|
||||
|
||||
// GetDocumentResponse returns the generated PDF content.
|
||||
message GetDocumentResponse {
|
||||
// Raw PDF bytes
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
- [x] Payments Orchestrator Service
|
||||
- [x] Chain Gateway Service
|
||||
- [x] MNTX Gateway Service
|
||||
- [x] TGSettle Gateway Service
|
||||
- [x] ChimeraSettle Gateway Service
|
||||
- [x] Notification Service
|
||||
- [x] BFF (Server) Service
|
||||
- [x] Frontend (Flutter Web)
|
||||
@@ -36,7 +36,7 @@
|
||||
- [x] ci/dev/payments-orchestrator.dockerfile
|
||||
- [x] ci/dev/chain-gateway.dockerfile
|
||||
- [x] ci/dev/mntx-gateway.dockerfile
|
||||
- [x] ci/dev/tgsettle-gateway.dockerfile
|
||||
- [x] ci/dev/chsettle-gateway.dockerfile
|
||||
- [x] ci/dev/notification.dockerfile
|
||||
- [x] ci/dev/bff.dockerfile
|
||||
- [x] ci/dev/frontend.dockerfile
|
||||
@@ -93,7 +93,7 @@ Service Layer:
|
||||
├─ dev-payments-orchestrator → [mongo, nats, ledger, billing-fees]
|
||||
├─ dev-chain-gateway → [mongo, nats, discovery, vault]
|
||||
├─ dev-mntx-gateway → [nats, discovery, vault]
|
||||
├─ dev-tgsettle-gateway → [mongo, nats, discovery, vault]
|
||||
├─ dev-chsettle-gateway → [mongo, nats, discovery, vault]
|
||||
├─ dev-notification → [nats]
|
||||
├─ dev-bff → [mongo, nats, ledger, payments, chain-gateway]
|
||||
└─ dev-frontend → [bff]
|
||||
@@ -120,7 +120,7 @@ Service Layer:
|
||||
### 4. Gateways
|
||||
- [ ] Chain gateway connects to Vault for keys
|
||||
- [ ] MNTX gateway is reachable
|
||||
- [ ] TGSettle gateway connects to Telegram
|
||||
- [ ] ChimeraSettle gateway is reachable and scenario routing works
|
||||
|
||||
### 5. Frontend
|
||||
- [ ] BFF serves API endpoints
|
||||
@@ -129,8 +129,8 @@ Service Layer:
|
||||
|
||||
## 🐛 Known Considerations
|
||||
|
||||
1. **Vault Secrets**: Services using Vault (chain, mntx, tgsettle) need secrets populated
|
||||
2. **External APIs**: MNTX and TGSettle need API credentials from Vault
|
||||
1. **Vault Secrets**: Services using Vault (chain, mntx, chsettle) need secrets populated
|
||||
2. **External APIs**: MNTX needs API credentials from Vault
|
||||
3. **Blockchain**: Chain gateway needs blockchain node URLs and private keys
|
||||
4. **Build Time**: Frontend build takes ~5-10 minutes (Flutter compile)
|
||||
|
||||
@@ -138,7 +138,7 @@ Service Layer:
|
||||
|
||||
- [ ] Populate Vault with blockchain keys for Chain Gateway
|
||||
- [ ] Add MNTX API credentials to Vault
|
||||
- [ ] Add TGSettle (Telegram) credentials to Vault
|
||||
- [ ] Validate ChimeraSettle scenario overrides in test flows
|
||||
- [ ] Seed test data into MongoDB
|
||||
- [ ] Configure blockchain RPC endpoints
|
||||
- [ ] Test full payment flow end-to-end
|
||||
|
||||
@@ -11,7 +11,7 @@ Docker Compose + Makefile build system for local development.
|
||||
|
||||
**Services:**
|
||||
- Discovery, Ledger, Billing Fees, Billing Documents, FX Oracle, Payments Orchestrator
|
||||
- Chain Gateway, MNTX Gateway, TGSettle Gateway
|
||||
- Chain Gateway, MNTX Gateway, ChimeraSettle Gateway
|
||||
- FX Ingestor, Notification, BFF (Server), Callbacks, Frontend
|
||||
|
||||
## Quick Start
|
||||
@@ -59,7 +59,7 @@ make status # Check service status
|
||||
|
||||
Examples:
|
||||
- Blockchain private keys (Chain Gateway)
|
||||
- External API keys (MNTX, TGSettle)
|
||||
- External API keys (MNTX)
|
||||
- Webhook signing secrets (Callbacks)
|
||||
- Production-like secrets
|
||||
|
||||
|
||||
36
ci/dev/chsettle-gateway.dockerfile
Normal file
36
ci/dev/chsettle-gateway.dockerfile
Normal file
@@ -0,0 +1,36 @@
|
||||
# Development Dockerfile for chsettle-gateway Service with Air hot reload
|
||||
|
||||
FROM golang:alpine AS builder
|
||||
|
||||
RUN apk add --no-cache bash git build-base protoc protobuf-dev && \
|
||||
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest && \
|
||||
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest && \
|
||||
go install github.com/air-verse/air@latest
|
||||
|
||||
WORKDIR /src
|
||||
|
||||
COPY api/proto ./api/proto
|
||||
COPY api/pkg ./api/pkg
|
||||
COPY api/gateway/common ./api/gateway/common
|
||||
COPY ci/scripts/proto/generate.sh ./ci/scripts/proto/
|
||||
RUN bash ci/scripts/proto/generate.sh
|
||||
|
||||
# Runtime stage for development with Air
|
||||
FROM golang:alpine
|
||||
|
||||
RUN apk add --no-cache bash git build-base && \
|
||||
go install github.com/air-verse/air@latest
|
||||
|
||||
WORKDIR /src
|
||||
|
||||
# Copy generated proto and pkg from builder
|
||||
COPY --from=builder /src/api/proto ./api/proto
|
||||
COPY --from=builder /src/api/pkg ./api/pkg
|
||||
COPY --from=builder /src/api/gateway/common ./api/gateway/common
|
||||
|
||||
# Source code will be mounted at runtime
|
||||
WORKDIR /src/api/gateway/chsettle
|
||||
|
||||
EXPOSE 50080 9406
|
||||
|
||||
CMD ["air", "-c", ".air.toml", "--", "-config.file", "/app/config.yml", "-debug"]
|
||||
@@ -13,10 +13,7 @@ ENV GO111MODULE=on
|
||||
ENV PATH="/go/bin:${PATH}"
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
RUN apk add --no-cache bash git build-base protoc protobuf-dev \
|
||||
&& go install google.golang.org/protobuf/cmd/protoc-gen-go@latest \
|
||||
&& go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest \
|
||||
&& bash ci/scripts/proto/generate.sh
|
||||
RUN apk add --no-cache git build-base
|
||||
WORKDIR /src/api/edge/bff
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
|
||||
@@ -13,10 +13,7 @@ ENV GO111MODULE=on
|
||||
ENV PATH="/go/bin:${PATH}"
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
RUN apk add --no-cache bash git build-base protoc protobuf-dev \
|
||||
&& go install google.golang.org/protobuf/cmd/protoc-gen-go@latest \
|
||||
&& go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest \
|
||||
&& bash ci/scripts/proto/generate.sh
|
||||
RUN apk add --no-cache git build-base
|
||||
WORKDIR /src/api/billing/documents
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
|
||||
@@ -13,10 +13,7 @@ ENV GO111MODULE=on
|
||||
ENV PATH="/go/bin:${PATH}"
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
RUN apk add --no-cache bash git build-base protoc protobuf-dev \
|
||||
&& go install google.golang.org/protobuf/cmd/protoc-gen-go@latest \
|
||||
&& go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest \
|
||||
&& bash ci/scripts/proto/generate.sh
|
||||
RUN apk add --no-cache git build-base
|
||||
WORKDIR /src/api/billing/fees
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
|
||||
@@ -13,10 +13,7 @@ ENV GO111MODULE=on
|
||||
ENV PATH="/go/bin:${PATH}"
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
RUN apk add --no-cache bash git build-base protoc protobuf-dev \
|
||||
&& go install google.golang.org/protobuf/cmd/protoc-gen-go@latest \
|
||||
&& go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest \
|
||||
&& bash ci/scripts/proto/generate.sh
|
||||
RUN apk add --no-cache git build-base
|
||||
WORKDIR /src/api/edge/callbacks
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
|
||||
@@ -13,10 +13,7 @@ ENV GO111MODULE=on
|
||||
ENV PATH="/go/bin:${PATH}"
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
RUN apk add --no-cache bash git build-base protoc protobuf-dev \
|
||||
&& go install google.golang.org/protobuf/cmd/protoc-gen-go@latest \
|
||||
&& go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest \
|
||||
&& bash ci/scripts/proto/generate.sh
|
||||
RUN apk add --no-cache git build-base
|
||||
WORKDIR /src/api/gateway/chain
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
|
||||
@@ -13,10 +13,7 @@ ENV GO111MODULE=on
|
||||
ENV PATH="/go/bin:${PATH}"
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
RUN apk add --no-cache bash git build-base protoc protobuf-dev \
|
||||
&& go install google.golang.org/protobuf/cmd/protoc-gen-go@latest \
|
||||
&& go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest \
|
||||
&& bash ci/scripts/proto/generate.sh
|
||||
RUN apk add --no-cache git build-base
|
||||
WORKDIR /src/api/discovery
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
|
||||
@@ -13,10 +13,7 @@ ENV GO111MODULE=on
|
||||
ENV PATH="/go/bin:${PATH}"
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
RUN apk add --no-cache bash git build-base protoc protobuf-dev \
|
||||
&& go install google.golang.org/protobuf/cmd/protoc-gen-go@latest \
|
||||
&& go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest \
|
||||
&& bash ci/scripts/proto/generate.sh
|
||||
RUN apk add --no-cache git build-base
|
||||
WORKDIR /src/api/fx/ingestor
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
|
||||
@@ -13,10 +13,7 @@ ENV GO111MODULE=on
|
||||
ENV PATH="/go/bin:${PATH}"
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
RUN apk add --no-cache bash git build-base protoc protobuf-dev \
|
||||
&& go install google.golang.org/protobuf/cmd/protoc-gen-go@latest \
|
||||
&& go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest \
|
||||
&& bash ci/scripts/proto/generate.sh
|
||||
RUN apk add --no-cache git build-base
|
||||
WORKDIR /src/api/fx/oracle
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
|
||||
@@ -13,10 +13,7 @@ ENV GO111MODULE=on
|
||||
ENV PATH="/go/bin:${PATH}"
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
RUN apk add --no-cache bash git build-base protoc protobuf-dev \
|
||||
&& go install google.golang.org/protobuf/cmd/protoc-gen-go@latest \
|
||||
&& go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest \
|
||||
&& bash ci/scripts/proto/generate.sh
|
||||
RUN apk add --no-cache git build-base
|
||||
WORKDIR /src/api/ledger
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
|
||||
@@ -13,10 +13,7 @@ ENV GO111MODULE=on
|
||||
ENV PATH="/go/bin:${PATH}"
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
RUN apk add --no-cache bash git build-base protoc protobuf-dev \
|
||||
&& go install google.golang.org/protobuf/cmd/protoc-gen-go@latest \
|
||||
&& go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest \
|
||||
&& bash ci/scripts/proto/generate.sh
|
||||
RUN apk add --no-cache git build-base
|
||||
WORKDIR /src/api/gateway/mntx
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
|
||||
@@ -13,10 +13,7 @@ ENV GO111MODULE=on
|
||||
ENV PATH="/go/bin:${PATH}"
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
RUN apk add --no-cache bash git build-base protoc protobuf-dev \
|
||||
&& go install google.golang.org/protobuf/cmd/protoc-gen-go@latest \
|
||||
&& go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest \
|
||||
&& bash ci/scripts/proto/generate.sh
|
||||
RUN apk add --no-cache git build-base
|
||||
WORKDIR /src/api/notification
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
|
||||
@@ -13,10 +13,7 @@ ENV GO111MODULE=on
|
||||
ENV PATH="/go/bin:${PATH}"
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
RUN apk add --no-cache bash git build-base protoc protobuf-dev \
|
||||
&& go install google.golang.org/protobuf/cmd/protoc-gen-go@latest \
|
||||
&& go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest \
|
||||
&& bash ci/scripts/proto/generate.sh
|
||||
RUN apk add --no-cache git build-base
|
||||
WORKDIR /src/api/payments/methods
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
|
||||
@@ -13,10 +13,7 @@ ENV GO111MODULE=on
|
||||
ENV PATH="/go/bin:${PATH}"
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
RUN apk add --no-cache bash git build-base protoc protobuf-dev \
|
||||
&& go install google.golang.org/protobuf/cmd/protoc-gen-go@latest \
|
||||
&& go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest \
|
||||
&& bash ci/scripts/proto/generate.sh
|
||||
RUN apk add --no-cache git build-base
|
||||
WORKDIR /src/api/payments/orchestrator
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
|
||||
@@ -13,10 +13,7 @@ ENV GO111MODULE=on
|
||||
ENV PATH="/go/bin:${PATH}"
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
RUN apk add --no-cache bash git build-base protoc protobuf-dev \
|
||||
&& go install google.golang.org/protobuf/cmd/protoc-gen-go@latest \
|
||||
&& go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest \
|
||||
&& bash ci/scripts/proto/generate.sh
|
||||
RUN apk add --no-cache git build-base
|
||||
WORKDIR /src/api/payments/quotation
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
|
||||
@@ -13,10 +13,7 @@ ENV GO111MODULE=on
|
||||
ENV PATH="/go/bin:${PATH}"
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
RUN apk add --no-cache bash git build-base protoc protobuf-dev \
|
||||
&& go install google.golang.org/protobuf/cmd/protoc-gen-go@latest \
|
||||
&& go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest \
|
||||
&& bash ci/scripts/proto/generate.sh
|
||||
RUN apk add --no-cache git build-base
|
||||
WORKDIR /src/api/gateway/tgsettle
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
|
||||
@@ -13,10 +13,7 @@ ENV GO111MODULE=on
|
||||
ENV PATH="/go/bin:${PATH}"
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
RUN apk add --no-cache bash git build-base protoc protobuf-dev \
|
||||
&& go install google.golang.org/protobuf/cmd/protoc-gen-go@latest \
|
||||
&& go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest \
|
||||
&& bash ci/scripts/proto/generate.sh
|
||||
RUN apk add --no-cache git build-base
|
||||
WORKDIR /src/api/gateway/tron
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
|
||||
@@ -73,6 +73,9 @@ if [ ! -d "${BUILD_CONTEXT}" ]; then
|
||||
BUILD_CONTEXT="/workspace"
|
||||
fi
|
||||
|
||||
KANIKO_CACHE_REPO="${KANIKO_CACHE_REPO:-${REGISTRY_URL}/kaniko-cache}"
|
||||
KANIKO_CACHE_TTL="${KANIKO_CACHE_TTL:-336h}"
|
||||
|
||||
/kaniko/executor \
|
||||
--context "${BUILD_CONTEXT}" \
|
||||
--dockerfile "${BFF_DOCKERFILE}" \
|
||||
@@ -82,4 +85,8 @@ fi
|
||||
--build-arg BUILD_BRANCH="${BUILD_BRANCH}" \
|
||||
--build-arg BUILD_DATE="${BUILD_DATE}" \
|
||||
--build-arg BUILD_USER="${BUILD_USER}" \
|
||||
--single-snapshot
|
||||
--cache=true \
|
||||
--cache-copy-layers \
|
||||
--cache-run-layers \
|
||||
--cache-repo "${KANIKO_CACHE_REPO}" \
|
||||
--cache-ttl "${KANIKO_CACHE_TTL}"
|
||||
|
||||
@@ -73,6 +73,9 @@ if [ ! -d "${BUILD_CONTEXT}" ]; then
|
||||
BUILD_CONTEXT="/workspace"
|
||||
fi
|
||||
|
||||
KANIKO_CACHE_REPO="${KANIKO_CACHE_REPO:-${REGISTRY_URL}/kaniko-cache}"
|
||||
KANIKO_CACHE_TTL="${KANIKO_CACHE_TTL:-336h}"
|
||||
|
||||
/kaniko/executor \
|
||||
--context "${BUILD_CONTEXT}" \
|
||||
--dockerfile "${DOCUMENTS_DOCKERFILE}" \
|
||||
@@ -82,4 +85,8 @@ fi
|
||||
--build-arg BUILD_BRANCH="${BUILD_BRANCH}" \
|
||||
--build-arg BUILD_DATE="${BUILD_DATE}" \
|
||||
--build-arg BUILD_USER="${BUILD_USER}" \
|
||||
--single-snapshot
|
||||
--cache=true \
|
||||
--cache-copy-layers \
|
||||
--cache-run-layers \
|
||||
--cache-repo "${KANIKO_CACHE_REPO}" \
|
||||
--cache-ttl "${KANIKO_CACHE_TTL}"
|
||||
|
||||
@@ -73,6 +73,9 @@ if [ ! -d "${BUILD_CONTEXT}" ]; then
|
||||
BUILD_CONTEXT="/workspace"
|
||||
fi
|
||||
|
||||
KANIKO_CACHE_REPO="${KANIKO_CACHE_REPO:-${REGISTRY_URL}/kaniko-cache}"
|
||||
KANIKO_CACHE_TTL="${KANIKO_CACHE_TTL:-336h}"
|
||||
|
||||
/kaniko/executor \
|
||||
--context "${BUILD_CONTEXT}" \
|
||||
--dockerfile "${FEES_DOCKERFILE}" \
|
||||
@@ -82,4 +85,8 @@ fi
|
||||
--build-arg BUILD_BRANCH="${BUILD_BRANCH}" \
|
||||
--build-arg BUILD_DATE="${BUILD_DATE}" \
|
||||
--build-arg BUILD_USER="${BUILD_USER}" \
|
||||
--single-snapshot
|
||||
--cache=true \
|
||||
--cache-copy-layers \
|
||||
--cache-run-layers \
|
||||
--cache-repo "${KANIKO_CACHE_REPO}" \
|
||||
--cache-ttl "${KANIKO_CACHE_TTL}"
|
||||
|
||||
@@ -73,6 +73,9 @@ if [ ! -d "${BUILD_CONTEXT}" ]; then
|
||||
BUILD_CONTEXT="/workspace"
|
||||
fi
|
||||
|
||||
KANIKO_CACHE_REPO="${KANIKO_CACHE_REPO:-${REGISTRY_URL}/kaniko-cache}"
|
||||
KANIKO_CACHE_TTL="${KANIKO_CACHE_TTL:-336h}"
|
||||
|
||||
/kaniko/executor \
|
||||
--context "${BUILD_CONTEXT}" \
|
||||
--dockerfile "${CALLBACKS_DOCKERFILE}" \
|
||||
@@ -82,4 +85,8 @@ fi
|
||||
--build-arg BUILD_BRANCH="${BUILD_BRANCH}" \
|
||||
--build-arg BUILD_DATE="${BUILD_DATE}" \
|
||||
--build-arg BUILD_USER="${BUILD_USER}" \
|
||||
--single-snapshot
|
||||
--cache=true \
|
||||
--cache-copy-layers \
|
||||
--cache-run-layers \
|
||||
--cache-repo "${KANIKO_CACHE_REPO}" \
|
||||
--cache-ttl "${KANIKO_CACHE_TTL}"
|
||||
|
||||
@@ -90,6 +90,9 @@ if [ ! -f "${BUILD_CONTEXT}/${CHAIN_GATEWAY_DOCKERFILE}" ]; then
|
||||
exit 68
|
||||
fi
|
||||
|
||||
KANIKO_CACHE_REPO="${KANIKO_CACHE_REPO:-${REGISTRY_URL}/kaniko-cache}"
|
||||
KANIKO_CACHE_TTL="${KANIKO_CACHE_TTL:-336h}"
|
||||
|
||||
/kaniko/executor \
|
||||
--context "${BUILD_CONTEXT}" \
|
||||
--dockerfile "${CHAIN_GATEWAY_DOCKERFILE}" \
|
||||
@@ -99,4 +102,8 @@ fi
|
||||
--build-arg BUILD_BRANCH="${BUILD_BRANCH}" \
|
||||
--build-arg BUILD_DATE="${BUILD_DATE}" \
|
||||
--build-arg BUILD_USER="${BUILD_USER}" \
|
||||
--single-snapshot
|
||||
--cache=true \
|
||||
--cache-copy-layers \
|
||||
--cache-run-layers \
|
||||
--cache-repo "${KANIKO_CACHE_REPO}" \
|
||||
--cache-ttl "${KANIKO_CACHE_TTL}"
|
||||
|
||||
@@ -73,6 +73,9 @@ if [ ! -d "${BUILD_CONTEXT}" ]; then
|
||||
BUILD_CONTEXT="/workspace"
|
||||
fi
|
||||
|
||||
KANIKO_CACHE_REPO="${KANIKO_CACHE_REPO:-${REGISTRY_URL}/kaniko-cache}"
|
||||
KANIKO_CACHE_TTL="${KANIKO_CACHE_TTL:-336h}"
|
||||
|
||||
/kaniko/executor \
|
||||
--context "${BUILD_CONTEXT}" \
|
||||
--dockerfile "${DISCOVERY_DOCKERFILE}" \
|
||||
@@ -82,4 +85,8 @@ fi
|
||||
--build-arg BUILD_BRANCH="${BUILD_BRANCH}" \
|
||||
--build-arg BUILD_DATE="${BUILD_DATE}" \
|
||||
--build-arg BUILD_USER="${BUILD_USER}" \
|
||||
--single-snapshot
|
||||
--cache=true \
|
||||
--cache-copy-layers \
|
||||
--cache-run-layers \
|
||||
--cache-repo "${KANIKO_CACHE_REPO}" \
|
||||
--cache-ttl "${KANIKO_CACHE_TTL}"
|
||||
|
||||
@@ -73,6 +73,9 @@ if [ ! -d "${BUILD_CONTEXT}" ]; then
|
||||
BUILD_CONTEXT="/workspace"
|
||||
fi
|
||||
|
||||
KANIKO_CACHE_REPO="${KANIKO_CACHE_REPO:-${REGISTRY_URL}/kaniko-cache}"
|
||||
KANIKO_CACHE_TTL="${KANIKO_CACHE_TTL:-336h}"
|
||||
|
||||
/kaniko/executor \
|
||||
--context "${BUILD_CONTEXT}" \
|
||||
--dockerfile "${FRONTEND_DOCKERFILE}" \
|
||||
@@ -82,4 +85,8 @@ fi
|
||||
--build-arg BUILD_BRANCH="${BUILD_BRANCH}" \
|
||||
--build-arg BUILD_DATE="${BUILD_DATE}" \
|
||||
--build-arg BUILD_USER="${BUILD_USER}" \
|
||||
--single-snapshot
|
||||
--cache=true \
|
||||
--cache-copy-layers \
|
||||
--cache-run-layers \
|
||||
--cache-repo "${KANIKO_CACHE_REPO}" \
|
||||
--cache-ttl "${KANIKO_CACHE_TTL}"
|
||||
|
||||
@@ -73,6 +73,9 @@ if [ ! -d "${BUILD_CONTEXT}" ]; then
|
||||
BUILD_CONTEXT="/workspace"
|
||||
fi
|
||||
|
||||
KANIKO_CACHE_REPO="${KANIKO_CACHE_REPO:-${REGISTRY_URL}/kaniko-cache}"
|
||||
KANIKO_CACHE_TTL="${KANIKO_CACHE_TTL:-336h}"
|
||||
|
||||
/kaniko/executor \
|
||||
--context "${BUILD_CONTEXT}" \
|
||||
--dockerfile "${FX_DOCKERFILE}" \
|
||||
@@ -82,4 +85,8 @@ fi
|
||||
--build-arg BUILD_BRANCH="${BUILD_BRANCH}" \
|
||||
--build-arg BUILD_DATE="${BUILD_DATE}" \
|
||||
--build-arg BUILD_USER="${BUILD_USER}" \
|
||||
--single-snapshot
|
||||
--cache=true \
|
||||
--cache-copy-layers \
|
||||
--cache-run-layers \
|
||||
--cache-repo "${KANIKO_CACHE_REPO}" \
|
||||
--cache-ttl "${KANIKO_CACHE_TTL}"
|
||||
|
||||
@@ -73,6 +73,9 @@ if [ ! -d "${BUILD_CONTEXT}" ]; then
|
||||
BUILD_CONTEXT="/workspace"
|
||||
fi
|
||||
|
||||
KANIKO_CACHE_REPO="${KANIKO_CACHE_REPO:-${REGISTRY_URL}/kaniko-cache}"
|
||||
KANIKO_CACHE_TTL="${KANIKO_CACHE_TTL:-336h}"
|
||||
|
||||
/kaniko/executor \
|
||||
--context "${BUILD_CONTEXT}" \
|
||||
--dockerfile "${LEDGER_DOCKERFILE}" \
|
||||
@@ -82,4 +85,8 @@ fi
|
||||
--build-arg BUILD_BRANCH="${BUILD_BRANCH}" \
|
||||
--build-arg BUILD_DATE="${BUILD_DATE}" \
|
||||
--build-arg BUILD_USER="${BUILD_USER}" \
|
||||
--single-snapshot
|
||||
--cache=true \
|
||||
--cache-copy-layers \
|
||||
--cache-run-layers \
|
||||
--cache-repo "${KANIKO_CACHE_REPO}" \
|
||||
--cache-ttl "${KANIKO_CACHE_TTL}"
|
||||
|
||||
@@ -90,6 +90,9 @@ if [ ! -f "${BUILD_CONTEXT}/${MNTX_GATEWAY_DOCKERFILE}" ]; then
|
||||
exit 68
|
||||
fi
|
||||
|
||||
KANIKO_CACHE_REPO="${KANIKO_CACHE_REPO:-${REGISTRY_URL}/kaniko-cache}"
|
||||
KANIKO_CACHE_TTL="${KANIKO_CACHE_TTL:-336h}"
|
||||
|
||||
/kaniko/executor \
|
||||
--context "${BUILD_CONTEXT}" \
|
||||
--dockerfile "${MNTX_GATEWAY_DOCKERFILE}" \
|
||||
@@ -99,4 +102,8 @@ fi
|
||||
--build-arg BUILD_BRANCH="${BUILD_BRANCH}" \
|
||||
--build-arg BUILD_DATE="${BUILD_DATE}" \
|
||||
--build-arg BUILD_USER="${BUILD_USER}" \
|
||||
--single-snapshot
|
||||
--cache=true \
|
||||
--cache-copy-layers \
|
||||
--cache-run-layers \
|
||||
--cache-repo "${KANIKO_CACHE_REPO}" \
|
||||
--cache-ttl "${KANIKO_CACHE_TTL}"
|
||||
|
||||
@@ -73,6 +73,9 @@ if [ ! -d "${BUILD_CONTEXT}" ]; then
|
||||
BUILD_CONTEXT="/workspace"
|
||||
fi
|
||||
|
||||
KANIKO_CACHE_REPO="${KANIKO_CACHE_REPO:-${REGISTRY_URL}/kaniko-cache}"
|
||||
KANIKO_CACHE_TTL="${KANIKO_CACHE_TTL:-336h}"
|
||||
|
||||
/kaniko/executor \
|
||||
--context "${BUILD_CONTEXT}" \
|
||||
--dockerfile "${NOTIFICATION_DOCKERFILE}" \
|
||||
@@ -82,4 +85,8 @@ fi
|
||||
--build-arg BUILD_BRANCH="${BUILD_BRANCH}" \
|
||||
--build-arg BUILD_DATE="${BUILD_DATE}" \
|
||||
--build-arg BUILD_USER="${BUILD_USER}" \
|
||||
--single-snapshot
|
||||
--cache=true \
|
||||
--cache-copy-layers \
|
||||
--cache-run-layers \
|
||||
--cache-repo "${KANIKO_CACHE_REPO}" \
|
||||
--cache-ttl "${KANIKO_CACHE_TTL}"
|
||||
|
||||
@@ -73,6 +73,9 @@ if [ ! -d "${BUILD_CONTEXT}" ]; then
|
||||
BUILD_CONTEXT="/workspace"
|
||||
fi
|
||||
|
||||
KANIKO_CACHE_REPO="${KANIKO_CACHE_REPO:-${REGISTRY_URL}/kaniko-cache}"
|
||||
KANIKO_CACHE_TTL="${KANIKO_CACHE_TTL:-336h}"
|
||||
|
||||
/kaniko/executor \
|
||||
--context "${BUILD_CONTEXT}" \
|
||||
--dockerfile "${PAYMENTS_METHODS_DOCKERFILE}" \
|
||||
@@ -82,4 +85,8 @@ fi
|
||||
--build-arg BUILD_BRANCH="${BUILD_BRANCH}" \
|
||||
--build-arg BUILD_DATE="${BUILD_DATE}" \
|
||||
--build-arg BUILD_USER="${BUILD_USER}" \
|
||||
--single-snapshot
|
||||
--cache=true \
|
||||
--cache-copy-layers \
|
||||
--cache-run-layers \
|
||||
--cache-repo "${KANIKO_CACHE_REPO}" \
|
||||
--cache-ttl "${KANIKO_CACHE_TTL}"
|
||||
|
||||
@@ -73,6 +73,9 @@ if [ ! -d "${BUILD_CONTEXT}" ]; then
|
||||
BUILD_CONTEXT="/workspace"
|
||||
fi
|
||||
|
||||
KANIKO_CACHE_REPO="${KANIKO_CACHE_REPO:-${REGISTRY_URL}/kaniko-cache}"
|
||||
KANIKO_CACHE_TTL="${KANIKO_CACHE_TTL:-336h}"
|
||||
|
||||
/kaniko/executor \
|
||||
--context "${BUILD_CONTEXT}" \
|
||||
--dockerfile "${PAYMENTS_DOCKERFILE}" \
|
||||
@@ -82,4 +85,8 @@ fi
|
||||
--build-arg BUILD_BRANCH="${BUILD_BRANCH}" \
|
||||
--build-arg BUILD_DATE="${BUILD_DATE}" \
|
||||
--build-arg BUILD_USER="${BUILD_USER}" \
|
||||
--single-snapshot
|
||||
--cache=true \
|
||||
--cache-copy-layers \
|
||||
--cache-run-layers \
|
||||
--cache-repo "${KANIKO_CACHE_REPO}" \
|
||||
--cache-ttl "${KANIKO_CACHE_TTL}"
|
||||
|
||||
@@ -73,6 +73,9 @@ if [ ! -d "${BUILD_CONTEXT}" ]; then
|
||||
BUILD_CONTEXT="/workspace"
|
||||
fi
|
||||
|
||||
KANIKO_CACHE_REPO="${KANIKO_CACHE_REPO:-${REGISTRY_URL}/kaniko-cache}"
|
||||
KANIKO_CACHE_TTL="${KANIKO_CACHE_TTL:-336h}"
|
||||
|
||||
/kaniko/executor \
|
||||
--context "${BUILD_CONTEXT}" \
|
||||
--dockerfile "${PAYMENTS_QUOTATION_DOCKERFILE}" \
|
||||
@@ -82,4 +85,8 @@ fi
|
||||
--build-arg BUILD_BRANCH="${BUILD_BRANCH}" \
|
||||
--build-arg BUILD_DATE="${BUILD_DATE}" \
|
||||
--build-arg BUILD_USER="${BUILD_USER}" \
|
||||
--single-snapshot
|
||||
--cache=true \
|
||||
--cache-copy-layers \
|
||||
--cache-run-layers \
|
||||
--cache-repo "${KANIKO_CACHE_REPO}" \
|
||||
--cache-ttl "${KANIKO_CACHE_TTL}"
|
||||
|
||||
@@ -90,6 +90,9 @@ if [ ! -f "${BUILD_CONTEXT}/${TGSETTLE_GATEWAY_DOCKERFILE}" ]; then
|
||||
exit 68
|
||||
fi
|
||||
|
||||
KANIKO_CACHE_REPO="${KANIKO_CACHE_REPO:-${REGISTRY_URL}/kaniko-cache}"
|
||||
KANIKO_CACHE_TTL="${KANIKO_CACHE_TTL:-336h}"
|
||||
|
||||
/kaniko/executor \
|
||||
--context "${BUILD_CONTEXT}" \
|
||||
--dockerfile "${TGSETTLE_GATEWAY_DOCKERFILE}" \
|
||||
@@ -99,4 +102,8 @@ fi
|
||||
--build-arg BUILD_BRANCH="${BUILD_BRANCH}" \
|
||||
--build-arg BUILD_DATE="${BUILD_DATE}" \
|
||||
--build-arg BUILD_USER="${BUILD_USER}" \
|
||||
--single-snapshot
|
||||
--cache=true \
|
||||
--cache-copy-layers \
|
||||
--cache-run-layers \
|
||||
--cache-repo "${KANIKO_CACHE_REPO}" \
|
||||
--cache-ttl "${KANIKO_CACHE_TTL}"
|
||||
|
||||
@@ -90,6 +90,9 @@ if [ ! -f "${BUILD_CONTEXT}/${TRON_GATEWAY_DOCKERFILE}" ]; then
|
||||
exit 68
|
||||
fi
|
||||
|
||||
KANIKO_CACHE_REPO="${KANIKO_CACHE_REPO:-${REGISTRY_URL}/kaniko-cache}"
|
||||
KANIKO_CACHE_TTL="${KANIKO_CACHE_TTL:-336h}"
|
||||
|
||||
/kaniko/executor \
|
||||
--context "${BUILD_CONTEXT}" \
|
||||
--dockerfile "${TRON_GATEWAY_DOCKERFILE}" \
|
||||
@@ -99,4 +102,8 @@ fi
|
||||
--build-arg BUILD_BRANCH="${BUILD_BRANCH}" \
|
||||
--build-arg BUILD_DATE="${BUILD_DATE}" \
|
||||
--build-arg BUILD_USER="${BUILD_USER}" \
|
||||
--single-snapshot
|
||||
--cache=true \
|
||||
--cache-copy-layers \
|
||||
--cache-run-layers \
|
||||
--cache-repo "${KANIKO_CACHE_REPO}" \
|
||||
--cache-ttl "${KANIKO_CACHE_TTL}"
|
||||
|
||||
@@ -779,15 +779,15 @@ services:
|
||||
VAULT_ADDR: ${VAULT_ADDR}
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# TGSettle Gateway Service (Telegram settlements)
|
||||
# ChimeraSettle Gateway Service (simulated settlements)
|
||||
# --------------------------------------------------------------------------
|
||||
dev-tgsettle-gateway:
|
||||
dev-chsettle-gateway:
|
||||
<<: *common-env
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ci/dev/tgsettle-gateway.dockerfile
|
||||
image: sendico-dev/tgsettle-gateway:latest
|
||||
container_name: dev-tgsettle-gateway
|
||||
dockerfile: ci/dev/chsettle-gateway.dockerfile
|
||||
image: sendico-dev/chsettle-gateway:latest
|
||||
container_name: dev-chsettle-gateway
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
dev-mongo-init: { condition: service_completed_successfully }
|
||||
@@ -795,29 +795,29 @@ services:
|
||||
dev-discovery: { condition: service_started }
|
||||
dev-vault: { condition: service_healthy }
|
||||
volumes:
|
||||
- ./api/gateway/tgsettle:/src/api/gateway/tgsettle
|
||||
- ./api/gateway/chsettle:/src/api/gateway/chsettle
|
||||
- ./api/gateway/common:/src/api/gateway/common
|
||||
- ./api/gateway/tgsettle/config.dev.yml:/app/config.yml:ro
|
||||
- ./api/gateway/chsettle/config.dev.yml:/app/config.yml:ro
|
||||
ports:
|
||||
- "50080:50080"
|
||||
- "9406:9406"
|
||||
networks:
|
||||
- sendico-dev
|
||||
environment:
|
||||
TGSETTLE_GATEWAY_MONGO_HOST: dev-mongo-1
|
||||
TGSETTLE_GATEWAY_MONGO_PORT: 27017
|
||||
TGSETTLE_GATEWAY_MONGO_DATABASE: tgsettle_gateway
|
||||
TGSETTLE_GATEWAY_MONGO_USER: ${MONGO_USER}
|
||||
TGSETTLE_GATEWAY_MONGO_PASSWORD: ${MONGO_PASSWORD}
|
||||
TGSETTLE_GATEWAY_MONGO_AUTH_SOURCE: admin
|
||||
TGSETTLE_GATEWAY_MONGO_REPLICA_SET: dev-rs
|
||||
CHSETTLE_GATEWAY_MONGO_HOST: dev-mongo-1
|
||||
CHSETTLE_GATEWAY_MONGO_PORT: 27017
|
||||
CHSETTLE_GATEWAY_MONGO_DATABASE: chsettle_gateway
|
||||
CHSETTLE_GATEWAY_MONGO_USER: ${MONGO_USER}
|
||||
CHSETTLE_GATEWAY_MONGO_PASSWORD: ${MONGO_PASSWORD}
|
||||
CHSETTLE_GATEWAY_MONGO_AUTH_SOURCE: admin
|
||||
CHSETTLE_GATEWAY_MONGO_REPLICA_SET: dev-rs
|
||||
NATS_HOST: dev-nats
|
||||
NATS_PORT: 4222
|
||||
NATS_USER: ${NATS_USER}
|
||||
NATS_PASSWORD: ${NATS_PASSWORD}
|
||||
NATS_URL: nats://${NATS_USER}:${NATS_PASSWORD}@dev-nats:4222
|
||||
TGSETTLE_GATEWAY_GRPC_PORT: 50080
|
||||
TGSETTLE_GATEWAY_METRICS_PORT: 9406
|
||||
CHSETTLE_GATEWAY_GRPC_PORT: 50080
|
||||
CHSETTLE_GATEWAY_METRICS_PORT: 9406
|
||||
VAULT_ADDR: ${VAULT_ADDR}
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user