638 Commits

Author SHA1 Message Date
Arseni
f44ef56ff3 WIP: integration with ledger 2026-02-04 02:01:22 +03:00
f1f16a30e6 Merge pull request 'improved message handling' (#402) from mntx-401 into main
Some checks failed
ci/woodpecker/push/billing_documents Pipeline failed
ci/woodpecker/push/bff Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/gateway_tron Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #402
2026-02-03 16:49:36 +00:00
Stephan D
979a0ac917 improved message handling 2026-02-03 17:49:10 +01:00
7d69e52679 Merge pull request 'tg fizx' (#401) from wp-399 into main
Some checks failed
ci/woodpecker/push/billing_documents Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/bff Pipeline failed
ci/woodpecker/push/gateway_tgsettle Pipeline failed
ci/woodpecker/push/gateway_tron Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline failed
ci/woodpecker/push/notification Pipeline failed
ci/woodpecker/push/payments_orchestrator Pipeline failed
ci/woodpecker/push/discovery Pipeline failed
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/gateway_chain Pipeline failed
ci/woodpecker/push/gateway_mntx Pipeline failed
Reviewed-on: #401
2026-02-03 15:11:41 +00:00
Stephan D
bbf781bba3 tg fizx 2026-02-03 16:10:47 +01:00
156152ede3 Merge pull request 'better logging + fixed tg messaging' (#400) from wp-399 into main
Some checks failed
ci/woodpecker/push/billing_documents Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/gateway_tron Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline failed
ci/woodpecker/push/notification Pipeline failed
Reviewed-on: #400
2026-02-03 14:19:35 +00:00
Stephan D
446d4d737c better logging + fixed tg messaging 2026-02-03 15:19:06 +01:00
b7ce4f7f4a Merge pull request 'fixed mntx deployment' (#398) from mntx-397 into main
All checks were successful
ci/woodpecker/push/billing_documents Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/gateway_tron Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #398
2026-02-03 11:17:36 +00:00
Stephan D
fccc29b8d8 fixed mntx deployment 2026-02-03 12:17:11 +01:00
3cdbf4ae31 Merge pull request 'fixed mntx deployment' (#397) from mntx-396 into main
Some checks failed
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/billing_documents Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline failed
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/ledger Pipeline failed
ci/woodpecker/push/gateway_tron Pipeline failed
Reviewed-on: #397
2026-02-03 10:36:13 +00:00
Stephan D
70cf849dfa fixed mntx deployment 2026-02-03 11:35:48 +01:00
e78011c234 Merge pull request 'fixed tg settlement amount' (#395) from tg-394 into main
All checks were successful
ci/woodpecker/push/billing_documents Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/gateway_tron Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #395
2026-02-02 23:54:16 +00:00
Stephan D
58e4ad379c fixed tg settlement amount 2026-02-03 00:53:53 +01:00
9255c7998d Merge pull request 'refactored payment orchestration' (#393) from po-392 into main
Some checks failed
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/gateway_tron Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_documents Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/discovery Pipeline failed
Reviewed-on: #393
2026-02-02 23:41:29 +00:00
Stephan D
5e87e2f2f9 refactored payment orchestration 2026-02-03 00:40:46 +01:00
05d998e0f7 Merge pull request 'TRON -> TRON_MAINNET' (#391) from tron-391 into main
All checks were successful
ci/woodpecker/push/billing_documents Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/gateway_tron Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #391
2026-02-01 02:36:24 +00:00
Stephan D
8faed5cbaa TRON -> TRON_MAINNET 2026-02-01 03:35:16 +01:00
be3fd6075f Merge pull request 'added logging' (#390) from tron-390 into main
Some checks failed
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/gateway_tron Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/billing_documents Pipeline failed
ci/woodpecker/push/bff Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/frontend Pipeline is running
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline is running
ci/woodpecker/push/payments_orchestrator Pipeline failed
Reviewed-on: #390
2026-02-01 01:04:18 +00:00
Stephan D
c16fa8104e added logging 2026-02-01 02:03:55 +01:00
433a0af5b4 Merge pull request 'fixed port exposure' (#389) from tron-389 into main
All checks were successful
ci/woodpecker/push/billing_documents Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/gateway_tron Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #389
2026-01-31 19:16:25 +00:00
Stephan D
8469d93cee fixed port exposure 2026-01-31 20:16:01 +01:00
fcd86816c6 Merge pull request 'tron build env updated' (#388) from tron-388 into main
Some checks failed
ci/woodpecker/push/billing_documents Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/gateway_tron Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #388
2026-01-31 10:43:51 +00:00
Stephan D
a8bf3b69e2 tron build env updated 2026-01-31 11:43:27 +01:00
c0cb7e6521 Merge pull request 'fixed docs build' (#387) from docs-387 into main
Some checks failed
ci/woodpecker/push/billing_documents Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline failed
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/gateway_tron Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #387
2026-01-30 23:53:16 +00:00
Stephan D
5fa15d39c8 fixed docs build 2026-01-31 00:52:50 +01:00
b2e8ff3279 Merge pull request 'trash removed' (#386) from trash-382 into main
Some checks failed
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/gateway_tron Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_documents Pipeline failed
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
Reviewed-on: #386
2026-01-30 23:37:05 +00:00
Stephan D
31adbd40cb trash removed 2026-01-31 00:36:32 +01:00
bea8f1bbf5 Merge pull request 'doc-381' (#384) from doc-381 into main
Some checks failed
ci/woodpecker/push/billing_documents Pipeline failed
ci/woodpecker/push/bff Pipeline failed
ci/woodpecker/push/billing_fees Pipeline is pending
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/discovery Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/gateway_tron Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
Reviewed-on: #384
2026-01-30 23:32:48 +00:00
Stephan D
d42dfb6070 version bump 2026-01-31 00:29:19 +01:00
Stephan D
1aa7e287fb fixed doc env vars + mongo v2 migration 2026-01-31 00:26:42 +01:00
cbb7bd8ba6 Merge pull request 'tron-381' (#382) from tron-381 into main
Some checks failed
ci/woodpecker/push/billing_documents Pipeline failed
ci/woodpecker/push/bff Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/discovery Pipeline failed
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/gateway_tgsettle Pipeline failed
ci/woodpecker/push/gateway_tron Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline failed
ci/woodpecker/push/gateway_mntx Pipeline failed
ci/woodpecker/push/ledger Pipeline failed
ci/woodpecker/push/notification Pipeline failed
ci/woodpecker/push/payments_orchestrator Pipeline failed
Reviewed-on: #382
2026-01-30 17:58:21 +00:00
c499fb7f9b Merge pull request 'visual fix for invitations from' (#379) from SEND040 into main
Some checks are pending
ci/woodpecker/push/billing_documents Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/bff Pipeline is pending
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/discovery Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/gateway_tron Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
Reviewed-on: #379
Reviewed-by: tech <tech.sendico@proton.me>
2026-01-30 17:58:08 +00:00
Stephan D
abf1a39d1a fixed tron build 2026-01-30 18:28:46 +01:00
Stephan D
8377b26c86 fixed tron env vars 2026-01-30 18:26:16 +01:00
9aaac3fdf2 Merge pull request 'fixed chain arb rpc url' (#380) from chain-378 into main
Some checks failed
ci/woodpecker/push/gateway_tron Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_documents Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline failed
ci/woodpecker/push/gateway_tgsettle Pipeline failed
Reviewed-on: #380
2026-01-30 17:12:20 +00:00
Stephan D
c2867a6ab1 fixed chain arb rpc url 2026-01-30 18:11:45 +01:00
Arseni
4064907921 visual fix for invitations from 2026-01-30 20:10:16 +03:00
37c8500811 Merge pull request 'dev cicd + tron + docs' (#377) from cicd-376 into main
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/billing_documents Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline failed
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/gateway_tron Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
Reviewed-on: #377
2026-01-30 16:04:55 +00:00
d16b64a9f2 Merge pull request 'mntx dev env' (#359) from mntx-358 into main
Some checks failed
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/discovery Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/bff Pipeline failed
Reviewed-on: #359
2026-01-30 16:04:34 +00:00
a9673c96c0 Merge pull request 'tron driver removed' (#357) from chain-356 into main
Reviewed-on: #357
2026-01-30 16:04:17 +00:00
0c0039888f Merge pull request 'discovery debugging env' (#351) from discovery-350 into main
Some checks failed
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/discovery Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/bff Pipeline failed
Reviewed-on: #351
2026-01-30 16:03:57 +00:00
4648d3ec0e Merge pull request 'new tron gateway' (#363) from tron-362 into main
Some checks failed
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/discovery Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/bff Pipeline failed
Reviewed-on: #363
2026-01-30 16:03:37 +00:00
4d58fdb1f1 Merge pull request 'front dev update' (#375) from front-374 into main
Some checks failed
ci/woodpecker/push/discovery Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/bff Pipeline failed
ci/woodpecker/push/billing_fees Pipeline failed
Reviewed-on: #375
2026-01-30 16:03:09 +00:00
6e66634ef0 Merge pull request 'bff dev upgrde' (#373) from bff-372 into main
Some checks failed
ci/woodpecker/push/bff Pipeline failed
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/discovery Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
Reviewed-on: #373
2026-01-30 16:02:57 +00:00
9819946449 Merge pull request 'notification dev env' (#367) from notification-366 into main
Some checks failed
ci/woodpecker/push/discovery Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/bff Pipeline failed
Reviewed-on: #367
2026-01-30 16:02:42 +00:00
70d06db1dc Merge pull request 'tgsettle dev env' (#361) from tg-360 into main
Some checks failed
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/discovery Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/bff Pipeline failed
Reviewed-on: #361
2026-01-30 16:02:26 +00:00
25e9744827 Merge pull request 'payments orchestrator refactoring' (#370) from payments-368 into main
Some checks failed
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/discovery Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/bff Pipeline failed
Reviewed-on: #370
2026-01-30 16:02:00 +00:00
ffc3d46c03 Merge pull request 'pkg update' (#371) from pkg-369 into main
Some checks failed
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/discovery Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/bff Pipeline failed
ci/woodpecker/push/billing_fees Pipeline failed
Reviewed-on: #371
2026-01-30 16:01:34 +00:00
a2f5fc1854 Merge pull request 'ledger accounts improvement' (#365) from ledger-364 into main
Reviewed-on: #365
2026-01-30 16:01:10 +00:00
73ad422d9c Merge pull request 'oracle-354' (#355) from oracle-354 into main
Some checks failed
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/discovery Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/bff Pipeline failed
ci/woodpecker/push/billing_fees Pipeline failed
Reviewed-on: #355
2026-01-30 16:00:38 +00:00
ac1e974d68 Merge pull request 'ingestor debugging env' (#353) from fx-352 into main
Some checks failed
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/discovery Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/bff Pipeline failed
ci/woodpecker/push/billing_fees Pipeline failed
Reviewed-on: #353
2026-01-30 16:00:03 +00:00
8e08c401bc Merge pull request 'granular fees plans' (#349) from fees-347 into main
Some checks failed
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/discovery Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/bff Pipeline failed
ci/woodpecker/push/billing_fees Pipeline failed
Reviewed-on: #349
2026-01-30 15:59:30 +00:00
be4ade91c4 Merge pull request 'billing docs service' (#348) from docs-346 into main
Some checks failed
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/discovery Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/bff Pipeline failed
ci/woodpecker/push/billing_fees Pipeline failed
Reviewed-on: #348
2026-01-30 15:59:16 +00:00
Stephan D
c1596296d1 dev cicd + tron + docs 2026-01-30 16:58:02 +01:00
Stephan D
102c5d3668 front dev update 2026-01-30 16:54:56 +01:00
Stephan D
e1f58b0982 bff dev upgrde 2026-01-30 16:39:12 +01:00
Stephan D
809370bda8 pkg update 2026-01-30 16:07:28 +01:00
Stephan D
73fadc9eb2 payments orchestrator refactoring 2026-01-30 16:03:08 +01:00
Stephan D
4a11bcb2c5 notification dev env 2026-01-30 16:00:06 +01:00
Stephan D
17dde423f6 ledger accounts improvement 2026-01-30 15:54:45 +01:00
Stephan D
8788ff67ec new tron gateway 2026-01-30 15:51:28 +01:00
Stephan D
c7c05ad8f6 tgsettle dev env 2026-01-30 15:48:45 +01:00
Stephan D
0e7f6ac9b2 mntx dev env 2026-01-30 15:45:50 +01:00
Stephan D
bc46eccbe0 tron driver removed 2026-01-30 15:42:50 +01:00
Stephan D
9417bfd456 - tmp files 2026-01-30 15:38:52 +01:00
Stephan D
c27b322b22 oracle dev env 2026-01-30 15:38:24 +01:00
Stephan D
f980d2caea ingestor debugging env 2026-01-30 15:36:00 +01:00
Stephan D
2cbc75bb8e discovery debugging env 2026-01-30 15:31:47 +01:00
Stephan D
d5016547d0 granular fees plans 2026-01-30 15:28:03 +01:00
Stephan D
7fbd88b6ef billing docs service 2026-01-30 15:16:20 +01:00
51f5b0804a Merge pull request 'refactoring for recipient addition page' (#344) from SEND039 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #344
Reviewed-by: tech <tech.sendico@proton.me>
2026-01-29 22:44:37 +00:00
Arseni
a3908cebba hotfix for payment page to see more then one payment type 2026-01-29 19:55:01 +03:00
Arseni
efa69b43b2 refactoring for recipient addition page 2026-01-29 19:22:30 +03:00
da8da04ae9 Merge pull request 'better ui/ux on 2fa page' (#334) from SEND038 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #334
Reviewed-by: tech <tech.sendico@proton.me>
2026-01-28 13:43:41 +00:00
8747d0be05 Merge pull request 'email placeholder to remind users which address to check for their code' (#333) from SEND037 into main
Some checks failed
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/discovery Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/bff Pipeline failed
Reviewed-on: #333
Reviewed-by: tech <tech.sendico@proton.me>
2026-01-28 13:43:32 +00:00
Arseni
0a27e0116a better ui/ux on 2fa page 2026-01-28 15:25:13 +03:00
Arseni
97dec6a8a0 email placeholder to remind users which address to check for their code 2026-01-28 14:50:11 +03:00
d78fe5daa0 Merge pull request 'Email Confirmation and refactor for snackbar' (#332) from SEND036 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #332
Reviewed-by: tech <tech.sendico@proton.me>
2026-01-27 16:11:58 +00:00
Arseni
6a3a60ef19 Small fixes 2026-01-27 18:41:14 +03:00
Arseni
be1d678c42 Email Confirmation and refactor for snackbar 2026-01-27 14:42:52 +03:00
e5cd0c9433 Merge pull request 'fixed logging' (#329) from fees-328 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #329
2026-01-27 04:35:10 +00:00
Stephan D
2bd3cef94a fixed logging 2026-01-26 10:52:09 +01:00
7391a67f82 Merge pull request 'ledger autoresolution' (#327) from ledger-326 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #327
2026-01-26 03:49:19 +00:00
Stephan D
81ba682d18 ledger autoresolution 2026-01-26 04:48:09 +01:00
dce0f2b467 Merge pull request 'observe.confirmation for chain gateway' (#325) from chain-324 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #325
2026-01-26 02:12:44 +00:00
Stephan D
0b2a993b6d observe.confirmation for chain gateway 2026-01-26 03:12:13 +01:00
5577bea038 Merge pull request 'fixed idempotency key' (#323) from front-320 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #323
2026-01-26 01:08:31 +00:00
bd99a8d398 Merge pull request 'payment observation step for mntx' (#322) from mntx-321 into main
Some checks failed
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/discovery Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/bff Pipeline failed
ci/woodpecker/push/billing_fees Pipeline failed
Reviewed-on: #322
2026-01-26 01:08:19 +00:00
Stephan D
3c0993686d payment observation step for mntx 2026-01-26 02:07:37 +01:00
Stephan D
197a0ba610 fixed idempotency key 2026-01-26 01:22:12 +01:00
97448a2f15 Merge pull request 'better error tracing' (#319) from quote-319 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #319
2026-01-25 23:55:49 +00:00
Stephan D
54f2f96e76 better error tracing 2026-01-26 00:54:03 +01:00
b349f2867f Merge pull request 'fixed condition' (#318) from quote-317 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #318
2026-01-25 22:37:05 +00:00
Stephan D
dcf8bdfba0 fixed condition 2026-01-25 23:36:40 +01:00
79b5d11ef4 Merge pull request 'Fixed payment method deletion in recipient settings with better flow' (#316) from SEND034 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #316
2026-01-23 21:26:55 +00:00
Arseni
3765780a4d Fixed payment method deletion in recipient settings with better flow 2026-01-23 16:28:09 +03:00
5161825bae Merge pull request 'fixed NATS configuration for fx' (#315) from fx-nats-314 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #315
2026-01-23 12:54:12 +00:00
Stephan D
debabf060d fixed NATS configuration for fx 2026-01-23 13:19:52 +01:00
f90bb53309 Merge pull request 'fx discovery fix' (#313) from fx-ingestor-312 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #313
2026-01-23 11:52:37 +00:00
Stephan D
e6519f4ba6 fx fix 2026-01-23 12:51:24 +01:00
bdb84ac6ac Merge pull request 'fx fix' (#311) from oracle-310 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #311
2026-01-23 10:51:05 +00:00
Stephan D
d7e029d421 fx fix 2026-01-23 11:50:41 +01:00
63d57d8a10 Merge pull request 'fixed ledger account listing + quotation listing' (#309) from quote-308 into main
All checks were successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #309
2026-01-23 01:48:54 +00:00
Stephan D
41f653775f fixed ledger account listing + quotation listing 2026-01-23 02:48:10 +01:00
Stephan D
218c4e20b3 accounts creation
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
2026-01-23 00:13:43 +01:00
b677d37b99 Merge pull request 'improved ledger account discovery' (#307) from ledger-306 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
Reviewed-on: #307
2026-01-22 19:06:10 +00:00
Stephan D
980c9fc9c7 improved ledger account discovery 2026-01-22 20:05:27 +01:00
c3226cb59e Merge pull request 'Implemented ledger provider' (#305) from ledger-300 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #305
2026-01-22 17:56:43 +00:00
Stephan D
7ae32cac55 Implemented ledger provider 2026-01-22 18:56:12 +01:00
1b59823105 Merge pull request 'Fixed wallets load' (#304) from wallets-303 into main
Some checks failed
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline failed
ci/woodpecker/push/ledger Pipeline failed
Reviewed-on: #304
2026-01-22 17:18:04 +00:00
Stephan D
71753e09ba Fixed wallets load 2026-01-22 18:17:41 +01:00
f202acd8ab Merge pull request 'fixed default wallet balance visibility' (#302) from visibility-301 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline failed
Reviewed-on: #302
2026-01-22 15:16:08 +00:00
Stephan D
acb257334f fixed default wallet balance visibility 2026-01-22 16:15:43 +01:00
1f135924f6 Merge pull request 'Fixed compilation' (#300) from ledger-299 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #300
2026-01-22 13:15:35 +00:00
Stephan D
32e8376700 Fixed compilation 2026-01-22 14:15:14 +01:00
8456263dd8 Merge pull request 'ledger-298' (#299) from ledger-298 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #299
2026-01-22 00:01:21 +00:00
Stephan D
8e46bc6061 ledger account service basis 2026-01-22 01:00:55 +01:00
Stephan D
62ff96b90e + ledger account ownerRef 2026-01-22 00:38:05 +01:00
eb4e7bc06a Merge pull request 'Fixed wallet creation logic: no owner for the wallet is allwoed' (#296) from chain-295 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #296
2026-01-21 21:28:21 +00:00
9d9d1ebdeb Merge pull request 'Quotation' (#297) from SEND033 into main
Some checks failed
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/discovery Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/bff Pipeline failed
ci/woodpecker/push/billing_fees Pipeline failed
Reviewed-on: #297
2026-01-21 21:28:09 +00:00
Arseni
636afe5d25 Fix 2026-01-22 00:00:42 +03:00
Arseni
6284625977 Quotation 2026-01-21 21:52:36 +03:00
Stephan D
8cb19f897a Fixed wallet creation logic: no owner for the wallet is allwoed 2026-01-21 17:26:45 +01:00
1e5ff51e07 Merge pull request 'Added popup for recipient deletion' (#293) from SEND032 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #293
2026-01-21 15:51:45 +00:00
859aeee08b Merge pull request 'idempotency key delivery fix' (#294) from payments-292 into main
Some checks failed
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/discovery Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/bff Pipeline failed
ci/woodpecker/push/billing_fees Pipeline failed
Reviewed-on: #294
2026-01-21 15:51:22 +00:00
Stephan D
bd5dfb4f26 idempotency key delivery fix 2026-01-21 16:50:47 +01:00
Arseni
d374bdc66c Added popup for recipient deletion 2026-01-21 18:12:32 +03:00
87f99be01d Merge pull request 'idempotency key usage fix' (#292) from payments-291 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #292
2026-01-21 14:24:54 +00:00
Stephan D
d2e78356e6 idempotency key usage fix 2026-01-21 15:23:50 +01:00
a15375f18e Merge pull request 'bettter message reaction and pending payments persistence' (#290) from tgsettle-289 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #290
2026-01-20 23:12:51 +00:00
Stephan D
0e933ace58 bettter message reaction and pending payments persistence 2026-01-21 00:12:32 +01:00
abc4ddfb5b Merge pull request 'new settlement flow' (#288) from notifications-287 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #288
2026-01-20 21:30:05 +00:00
Stephan D
e0d7320fad new settlement flow 2026-01-20 22:29:30 +01:00
ae6c617136 Merge pull request 'fixed tgsettle logging' (#280) from tgsettle-279 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #280
2026-01-19 18:56:58 +00:00
Stephan D
5737ebf89a fixed tgsettle logging 2026-01-19 19:56:11 +01:00
d9d2fded8a Merge pull request 'fixed tgsettle discovery advertisement' (#278) from discovery-277 into main
All checks were successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
Reviewed-on: #278
2026-01-19 15:52:45 +00:00
Stephan D
f10ad5ba1e fixed tgsettle discovery advertisement 2026-01-19 16:50:39 +01:00
1e18764a75 Merge pull request 'fixed settlement flow' (#276) from settlement-275 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
Reviewed-on: #276
2026-01-19 14:27:01 +00:00
Stephan D
069ff6b26b fixed settlement flow 2026-01-19 15:26:34 +01:00
0b2a13feff Merge pull request 'payments-273' (#274) from payments-273 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #274
2026-01-19 11:56:25 +00:00
Stephan D
2adcdb0b43 fixed plan execution 2026-01-19 12:56:06 +01:00
Stephan D
f84d52ac14 enhanced paymemnt route handling error 2026-01-19 12:14:54 +01:00
c13ea01130 Merge pull request 'discovery: +invoke url' (#271) from discovery-270 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #271
2026-01-19 10:07:54 +00:00
Stephan D
64803a21e0 discovery: +invoke url 2026-01-19 11:07:21 +01:00
1eb5a918a0 Merge pull request 'fixed orchestrator compilaiton' (#269) from payments-268 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #269
2026-01-18 14:16:26 +00:00
Stephan D
5cd8ac0519 fixed orchestrator compilaiton 2026-01-18 15:15:56 +01:00
1d21991cd7 Merge pull request 'better logging' (#267) from tg-266 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline failed
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline failed
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
Reviewed-on: #267
2026-01-18 12:11:41 +00:00
Stephan D
3db1681a6e better logging 2026-01-18 13:11:22 +01:00
66a3961cef Merge pull request 'Switched to real tg chat' (#265) from tg-264 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
Reviewed-on: #265
2026-01-16 14:21:19 +00:00
Stephan D
4ddfdc10be Switched to real tg chat 2026-01-16 15:20:56 +01:00
10a2e5e528 Merge pull request 'hr-263' (#264) from hr-263 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
Reviewed-on: #264
2026-01-16 13:38:43 +00:00
Stephan D
0082b590ac removed plan script 2026-01-16 14:38:00 +01:00
Stephan D
426954ed20 deps bump 2026-01-16 14:36:28 +01:00
Stephan D
a4333a5385 hold/release + discovery based routing 2026-01-16 14:33:05 +01:00
fe0caaa611 Merge pull request 'minor cleanup' (#262) from flutter-264 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
Reviewed-on: #262
2026-01-16 11:09:24 +00:00
Stephan D
4cd4bfe7be minor cleanup 2026-01-16 12:08:52 +01:00
67a9b72a3f Merge pull request 'Added placeholder for lastName and role addition functionality' (#249) from SEND027 into main
Some checks failed
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/discovery Pipeline failed
Reviewed-on: #249
2026-01-16 11:00:49 +00:00
000d3c179b Merge branch 'main' into SEND027 2026-01-16 11:00:33 +00:00
Stephan D
0d444e5ff4 last name support added 2026-01-16 11:58:47 +01:00
e398810c70 Merge pull request 'temp analyzer fix' (#261) from flutter-260 into main
Some checks failed
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
Reviewed-on: #261
2026-01-16 10:39:21 +00:00
Stephan D
455afe99e7 temp analyzer fix 2026-01-16 11:39:01 +01:00
4f8e0b5e6c Merge pull request 'fixed serialization/deserialization' (#259) from chain-258 into main
Some checks failed
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
Reviewed-on: #259
2026-01-15 19:03:05 +00:00
Stephan D
0d6e16711f fixed serialization/deserialization 2026-01-15 20:02:03 +01:00
b512da71de Merge pull request 'Fixed messaging buffering issue' (#257) from nats-256 into main
Some checks failed
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
Reviewed-on: #257
2026-01-15 17:53:29 +00:00
Stephan D
4786df60ae Fixed messaging buffering issue 2026-01-15 18:52:14 +01:00
c775b3fdd4 Merge pull request 'Added missing localizations' (#255) from SEND029 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
Reviewed-on: #255
Reviewed-by: tech <tech.sendico@proton.me>
2026-01-15 11:40:30 +00:00
Arseni
6a2d1b34e4 Added missing localizations 2026-01-15 11:05:15 +03:00
Arseni
3242fc3744 Fix for build to run 2026-01-14 19:35:43 +03:00
Arseni
9319108b26 Added placeholder for lastName and role addition functionality
Try to rebase
2026-01-14 19:35:15 +03:00
6bc5130883 Merge pull request 'Moved the payment flow providers from the global level into the payout shell' (#247) from SEND026 into main
Some checks failed
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
Reviewed-on: #247
2026-01-14 16:29:24 +00:00
3a7b2a3b28 Merge pull request 'Added dialog window to confirm or reject processed payment' (#250) from SEND028 into main
Reviewed-on: #250
Reviewed-by: tech <tech.sendico@proton.me>
2026-01-14 16:28:55 +00:00
0245b679d2 Merge pull request 'fixed wallet listing ignoring org reference' (#252) from wallets-251 into main
Some checks failed
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/discovery Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/bff Pipeline failed
Reviewed-on: #252
2026-01-14 16:25:45 +00:00
Stephan D
343911ebe7 fixed wallet listing ignoring org reference 2026-01-14 17:25:21 +01:00
Arseni
7fb413fd9b Moved the payment flow providers from the global level into the payout shell
Try to rebase
2026-01-14 19:11:39 +03:00
Arseni
abb428e891 Added dialog window to confirm or reject processed payment 2026-01-14 18:51:40 +03:00
62bc2644d4 Merge pull request 'Sender Invitation' (#245) from SEND024 into main
All checks were successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
Reviewed-on: #245
Reviewed-by: tech <tech.sendico@proton.me>
2026-01-13 23:48:33 +00:00
aa70f54021 Merge pull request 'Card expiry date and few small fixes' (#244) from SEND023 into main
Some checks failed
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/discovery Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/bff Pipeline failed
Reviewed-on: #244
Reviewed-by: tech <tech.sendico@proton.me>
2026-01-13 23:41:04 +00:00
Arseni
5447433b5d Sender Invitation 2026-01-12 21:28:18 +03:00
Arseni
0cb5101ed9 Card expiry date and few small fixes 2026-01-12 21:24:58 +03:00
dedde76dd7 Merge pull request 'Added ownership reference + wallet creation methods' (#243) from owner-242 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #243
2026-01-07 12:14:59 +00:00
Stephan D
9e747e7251 Added ownership reference + wallet creation methods 2026-01-07 13:12:31 +01:00
33647a0f3d Merge pull request 'ledger settlement account autocreation' (#241) from ledger-237 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/gateway_chain Pipeline failed
ci/woodpecker/push/gateway_mntx Pipeline failed
ci/woodpecker/push/ledger Pipeline failed
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline failed
ci/woodpecker/push/notification Pipeline was successful
Reviewed-on: #241
2026-01-06 18:08:18 +00:00
Stephan D
890f78a42e ledger settlement account autocreation 2026-01-06 19:06:15 +01:00
c0ba167f69 Merge pull request 'compilation fix' (#239) from ledger-237 into main
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline failed
ci/woodpecker/push/gateway_mntx Pipeline failed
ci/woodpecker/push/gateway_tgsettle Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline failed
ci/woodpecker/push/notification Pipeline was successful
Reviewed-on: #239
2026-01-06 17:05:26 +00:00
Stephan D
3aa5d56cc3 compilation fiz 2026-01-06 18:04:56 +01:00
326fc5a885 Merge pull request 'ledger account describibale support' (#238) from ledger-237 into main
Some checks failed
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/fx_oracle Pipeline failed
Reviewed-on: #238
2026-01-06 16:52:09 +00:00
Stephan D
43edbc109d ledger account describibale support 2026-01-06 17:51:35 +01:00
12700c5595 Merge pull request 'fixed excessive logging non-nil checks)' (#236) from logging-235 into main
Reviewed-on: #236
2026-01-06 15:10:05 +00:00
Stephan D
4da9e0b522 fixed excessive logging non-nil checks) 2026-01-06 16:05:20 +01:00
5d443230f4 Merge pull request 'TTL for discovery values' (#234) from discovery-233 into main
Some checks failed
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/frontend Pipeline is running
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline is running
ci/woodpecker/push/notification Pipeline failed
ci/woodpecker/push/payments_orchestrator Pipeline failed
Reviewed-on: #234
2026-01-06 13:20:27 +00:00
Stephan D
3e83cc51d7 TTL for discovery values 2026-01-06 14:20:08 +01:00
9c2ef52d07 Merge pull request '+ ledger account open endpoint' (#232) from ledger-231 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
Reviewed-on: #232
2026-01-05 12:03:10 +00:00
Stephan D
e84854d875 fixed mntx compilation 2026-01-05 13:02:47 +01:00
Stephan D
2f34b5a827 + ledger account open endpoint 2026-01-05 12:57:17 +01:00
9a5c087940 Merge pull request 'compilation fixed' (#230) from mntx-229 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline failed
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #230
2026-01-05 01:52:23 +00:00
Stephan D
4fb2e0433c compilation fixed 2026-01-05 02:51:39 +01:00
cd89171cf0 Merge pull request 'interface refactoring' (#228) from gateway-227 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline failed
ci/woodpecker/push/ledger Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #228
2026-01-05 00:23:43 +00:00
Stephan D
7424ef751c interface refactoring 2026-01-05 01:22:47 +01:00
fcd831902a Merge pull request 'nats-225' (#226) from nats-225 into main
All checks were successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #226
2026-01-04 13:50:07 +00:00
Stephan D
03f4988a99 fixed mntx build 2026-01-04 14:46:20 +01:00
Stephan D
5684a959f5 isolated NATS logic 2026-01-04 14:44:46 +01:00
94406f65cb Merge pull request 'fixed discovery grpc port' (#224) from tgsettle-223 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline failed
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #224
2026-01-04 13:00:08 +00:00
Stephan D
49ba144d8c fixed discovery grpc port 2026-01-04 13:59:39 +01:00
2c5f2b8cb1 Merge pull request 'tgsettle gateway build added' (#222) from tgsettle-221 into main
Some checks failed
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_mntx Pipeline is pending
ci/woodpecker/push/gateway_tgsettle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/frontend Pipeline is running
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline is running
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/discovery Pipeline failed
Reviewed-on: #222
2026-01-04 12:13:36 +00:00
Stephan D
ee28c13558 tgsettle gateway build added 2026-01-04 13:12:49 +01:00
6a57afc057 Merge pull request 'discovery-216' (#220) from discovery-216 into main
Some checks failed
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/discovery Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
Reviewed-on: #220
2026-01-04 11:59:01 +00:00
Stephan D
59c83e414a unified gateway interfaces 2026-01-04 12:57:40 +01:00
Stephan D
743f683d92 TG settlement service 2026-01-04 12:57:40 +01:00
Stephan D
ea1c69f14a discovery service 2026-01-04 12:57:40 +01:00
Stephan D
97ba7500dc unified gateway interface 2026-01-04 12:57:40 +01:00
19b7b69bd8 Merge pull request 'Refresh button for balance' (#219) from SEND022 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline failed
Reviewed-on: #219
2025-12-30 21:14:55 +00:00
Arseni
b157522fdb Refresh button for balance 2025-12-30 18:36:29 +03:00
202582626a Merge pull request 'fixed signature check' (#215) from signature-214 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #215
2025-12-29 23:23:27 +00:00
Stephan D
6a2efd3d22 fixed signature check 2025-12-30 00:22:49 +01:00
a6374d1136 Merge pull request 'increased payout timeout' (#213) from timeout-210 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #213
2025-12-29 15:43:48 +00:00
Stephan D
7c864dc304 increased payout timeout 2025-12-29 16:43:03 +01:00
4aeb06fd31 Merge pull request 'Payments listing method' (#209) from payments-208 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #209
2025-12-29 13:29:46 +00:00
Stephan D
d1786dc5d9 Payments listing method 2025-12-29 14:27:32 +01:00
f5bf8cf6d0 Merge pull request 'Finally Fixed search field in payment page and cleaned up payment flow' (#204) from SEND020 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #204
2025-12-26 19:35:16 +00:00
7daa4ab027 Merge pull request 'temp restrictions removal + better request callback logging' (#205) from mntx-204 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #205
2025-12-26 18:18:57 +00:00
Stephan D
6f2309669b temp restrictions removal + better request callback logging 2025-12-26 19:18:35 +01:00
Arseni
e4847cd137 Finally Fixed search field in payment page and cleaned up payment flow 2025-12-26 20:37:59 +03:00
dbd06a4162 Merge pull request 'fixed address normalizatoin' (#203) from tron-202 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #203
2025-12-26 16:25:01 +00:00
Stephan D
1ec6cd8386 fixed address normalizatoin 2025-12-26 17:24:43 +01:00
6daf567baf Merge pull request 'improved FX logging' (#197) from fx-196 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
Reviewed-on: #197
2025-12-26 14:15:01 +00:00
23a57e543d Merge pull request 'payment recipient data' (#199) from mntx-198 into main
Some checks failed
ci/woodpecker/push/chain_gateway Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/bff Pipeline failed
Reviewed-on: #199
2025-12-26 14:14:52 +00:00
Stephan D
8adfab94b5 payment recipient data 2025-12-26 15:14:31 +01:00
Stephan D
db488a31e8 improved FX logging 2025-12-26 14:25:18 +01:00
3836ff5ef3 Merge pull request 'Got rid of deprecated methods' (#191) from SEND019 into main
Some checks failed
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline failed
Reviewed-on: #191
Reviewed-by: tech <tech.sendico@proton.me>
2025-12-26 13:09:55 +00:00
aef5c99a22 Merge pull request 'wallet search fix' (#195) from chain-190 into main
Some checks failed
ci/woodpecker/push/chain_gateway Pipeline is pending
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/bff Pipeline failed
Reviewed-on: #195
2025-12-26 13:09:42 +00:00
Stephan D
be7c965234 wallet search fix 2025-12-26 14:09:16 +01:00
Arseni
63448ab267 got rid of deprecated methods 2025-12-26 15:04:41 +03:00
34a565d86d Merge pull request 'improved logging + autotests' (#189) from mntx-188 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #189
2025-12-26 11:26:52 +00:00
Stephan D
171d90b3f7 improved logging + autotests 2025-12-26 12:26:28 +01:00
5191336a49 Merge pull request 'extended logging + wallet referencing improved' (#186) from tron-185 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #186
2025-12-26 00:31:34 +00:00
Stephan D
48f64a722d extended logging + wallet referencing improved 2025-12-26 01:31:15 +01:00
bde453d106 Merge pull request 'fixed wallet fetcher + removed excessive logging' (#184) from tron-183 into main
Some checks failed
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/chain_gateway Pipeline is pending
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/bff Pipeline failed
Reviewed-on: #184
2025-12-26 00:22:41 +00:00
Stephan D
3bb33b8895 fixed wallet fetcher 2025-12-26 01:21:16 +01:00
8ee092089f Merge pull request 'replaced evm function for tron' (#182) from tron-182 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/ledger Pipeline failed
ci/woodpecker/push/mntx_gateway Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline failed
ci/woodpecker/push/payments_orchestrator Pipeline failed
Reviewed-on: #182
2025-12-25 23:53:46 +00:00
Stephan D
eca3d0d62e replaced evm function for tron 2025-12-26 00:53:25 +01:00
aba743406a Merge pull request 'temp extended request logging' (#181) from log-181 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #181
2025-12-25 21:36:19 +00:00
Stephan D
deb29efde3 temp extended request logging 2025-12-25 22:31:00 +01:00
6995afc47d Merge pull request 'extended logging' (#180) from log-180 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/ledger Pipeline failed
ci/woodpecker/push/mntx_gateway Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline failed
ci/woodpecker/push/payments_orchestrator Pipeline failed
Reviewed-on: #180
2025-12-25 21:04:18 +00:00
Stephan D
7b645a3bbe extended logging 2025-12-25 22:02:15 +01:00
0ddd92b88b Merge pull request 'extended logging' (#179) from log-179 into main
Some checks failed
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
Reviewed-on: #179
2025-12-25 20:50:05 +00:00
Stephan D
6151e3d3a5 extended logging 2025-12-25 21:49:44 +01:00
af7abbb095 Merge pull request 'extended logging' (#178) from log-178 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #178
2025-12-25 20:01:55 +00:00
Stephan D
71be1ef9f0 extended logging 2025-12-25 21:01:37 +01:00
3df358d865 Merge pull request 'fixed trx source' (#177) from gas-176 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/chain_gateway Pipeline was successful
Reviewed-on: #177
2025-12-25 19:36:33 +00:00
Stephan D
c6b2ba486b fixed trx source 2025-12-25 20:35:57 +01:00
d324e455cc Merge pull request 'fixed self sending TRX issue' (#175) from gas-171 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline failed
ci/woodpecker/push/notification Pipeline failed
Reviewed-on: #175
2025-12-25 18:54:31 +00:00
Stephan D
8c87e5534e fixed self sending TRX issue 2025-12-25 19:54:01 +01:00
bcb3e9e647 Merge pull request 'added mntx client to payment orchestration' (#172) from mntx-170 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #172
2025-12-25 17:23:58 +00:00
Stephan D
43f26143df added mntx client to payment orchestration 2025-12-25 18:23:08 +01:00
ed6e6bf1ba Merge pull request 'payment button connected + supported payment by quote reference' (#168) from pay-167 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #168
2025-12-25 16:24:55 +00:00
Stephan D
2d38b974ba improved logging 2025-12-25 17:01:35 +01:00
Stephan D
610296b301 improved logging 2025-12-25 17:01:05 +01:00
Stephan D
fcc68c8380 payment button connected 2025-12-25 16:56:35 +01:00
b96babdfd4 Merge pull request 'new mntx funding wallet address' (#165) from mntx-164 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #165
2025-12-25 13:19:17 +00:00
69fdbf4e95 Merge pull request 'Fixed payment information form in address recipient book and fixed some headers' (#163) from SEND016 into main
Some checks failed
ci/woodpecker/push/chain_gateway Pipeline is pending
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/bff Pipeline failed
Reviewed-on: #163
Reviewed-by: tech <tech.sendico@proton.me>
2025-12-25 13:18:37 +00:00
Stephan D
d32b2aa959 new mntx funding wallet address 2025-12-25 14:18:18 +01:00
Arseni
be10839e3a Fixed payment information form in address recipient book and fixed some headers 2025-12-25 15:10:20 +03:00
d530af43a1 Merge pull request 'EVM, ARB, ETH gas top up policies + tron config change' (#162) from tron-161 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
Reviewed-on: #162
2025-12-25 11:54:02 +00:00
Stephan D
aa673fb26d EVM, ARB, ETH gas top up policies + tron config change 2025-12-25 12:52:34 +01:00
d978e24a9d Merge pull request 'Gas topup limits' (#160) from tron-159 into main
Some checks failed
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline failed
Reviewed-on: #160
2025-12-25 11:29:45 +00:00
Stephan D
31d93e5113 Gas topup limits 2025-12-25 12:26:24 +01:00
f02f3449f3 Merge pull request 'gas tanking before transaction' (#158) from tron-157 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #158
2025-12-25 10:30:05 +00:00
Stephan D
d46822b9bb gas tanking before transaction 2025-12-25 11:25:13 +01:00
0505b2314e Merge pull request 'quotation provider now uses payment methods as source for quotation' (#156) from flow-153 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #156
2025-12-24 19:40:15 +00:00
Stephan D
407e704352 quotation provider now uses payment methods as source for quotation 2025-12-24 20:39:17 +01:00
4251dfb2c6 Merge pull request 'added wallet source to quotation preparation' (#152) from wallet-151 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline failed
ci/woodpecker/push/payments_orchestrator Pipeline failed
Reviewed-on: #152
2025-12-24 19:00:24 +00:00
Stephan D
e0820c47c2 added wallet source to quotation preparation 2025-12-24 19:59:50 +01:00
68b82cbca2 Merge pull request 'chain network name display fixed' (#147) from wallet-147 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
Reviewed-on: #147
2025-12-24 17:18:13 +00:00
Stephan D
9e6d530385 chain network name display fixed 2025-12-24 18:17:35 +01:00
5836292adb Merge pull request 'Added Last Name display and made it editable' (#145) from SEND015 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #145
2025-12-24 16:08:40 +00:00
0c6229331f Merge pull request 'Password field checks for match with old password from db and check so that new password feild matches with the confirm password field' (#143) from SEND013 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/chain_gateway Pipeline is pending
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/bff Pipeline failed
Reviewed-on: #143
2025-12-24 16:07:58 +00:00
8cb6a64f2b Merge pull request 'Got rid of bools in 2fa provider' (#144) from SEND014 into main
Some checks failed
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/chain_gateway Pipeline is pending
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/bff Pipeline failed
Reviewed-on: #144
2025-12-24 16:07:07 +00:00
Arseni
4453dab366 Added Last Name display and made it editable 2025-12-24 18:48:33 +03:00
Arseni
512f25f74f Got rid of bools in 2fa provider 2025-12-24 16:26:22 +03:00
Arseni
43020f3eb6 Password field checks for match with old password from db and check so that new password feild matches with the confirm password field 2025-12-24 16:18:52 +03:00
964e90767d Merge pull request 'tron refactoring' (#142) from tron-150 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #142
2025-12-24 12:20:46 +00:00
Stephan D
03cd2f4784 tron refactoring 2025-12-24 13:20:25 +01:00
2d735aa7f5 Merge pull request 'hex parser + test' (#141) from tron-148 into main
Some checks failed
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
Reviewed-on: #141
2025-12-24 02:53:38 +00:00
Stephan D
342dd5328f hex parser + test 2025-12-24 03:53:20 +01:00
915ed66b08 Merge pull request 'fixed big int reader' (#140) from tron-146 into main
Some checks failed
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/chain_gateway Pipeline was successful
Reviewed-on: #140
2025-12-24 02:15:36 +00:00
Stephan D
fe73b3078a fixed big int reader 2025-12-24 03:15:12 +01:00
76204822e7 Merge pull request 'fixed proto message' (#139) from tron-142 into main
Some checks failed
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
Reviewed-on: #139
2025-12-24 01:57:36 +00:00
Stephan D
77c205f9b2 fixed proto message 2025-12-24 02:57:15 +01:00
6a29dc8907 Merge pull request 'compilation fix' (#138) from tron-144 into main
Some checks failed
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
Reviewed-on: #138
2025-12-24 01:17:24 +00:00
Stephan D
8f1f279792 compilation fix 2025-12-24 02:17:01 +01:00
1f0b54d590 Merge pull request 'extended logging + timeout setting' (#137) from tron-140 into main
Some checks failed
ci/woodpecker/push/chain_gateway Pipeline failed
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
Reviewed-on: #137
2025-12-24 01:00:20 +00:00
Stephan D
cefb9706f9 extended logging + timeout setting 2025-12-24 01:59:37 +01:00
79b7899658 Merge pull request 'refactored initialization' (#136) from tron-138 into main
Some checks failed
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
Reviewed-on: #136
2025-12-24 00:32:09 +00:00
Stephan D
c941319c4e refactored initialization 2025-12-24 01:31:43 +01:00
e6626600cc Merge pull request 'extra logging' (#135) from tron-136 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #135
2025-12-23 17:36:51 +00:00
Stephan D
e74c06e87a extra logging 2025-12-23 18:36:22 +01:00
c3647bfc46 Merge pull request 'version bump' (#134) from tron-136 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/ledger Pipeline failed
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline failed
ci/woodpecker/push/payments_orchestrator Pipeline failed
Reviewed-on: #134
2025-12-23 16:43:46 +00:00
Stephan D
3ff81038a9 version bump 2025-12-23 17:43:20 +01:00
d6d9d47e67 Merge pull request 'Added new tron networks' (#133) from tron-134 into main
Some checks failed
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/fx_ingestor Pipeline failed
Reviewed-on: #133
2025-12-23 16:23:50 +00:00
Stephan D
034eb943e2 Added new tron networks 2025-12-23 17:21:58 +01:00
93bd0bf002 Merge pull request 'fixed config + improved logging' (#132) from tron-132 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline failed
ci/woodpecker/push/notification Pipeline failed
Reviewed-on: #132
2025-12-23 15:28:27 +00:00
Stephan D
946bfa217c fixed config + improved logging 2025-12-23 16:26:06 +01:00
318255405b Merge pull request 'Migration to TRON chain' (#130) from tron-130 into main
Some checks are pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/frontend Pipeline is running
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline is running
Reviewed-on: #130
2025-12-23 14:42:30 +00:00
Stephan D
19d4ee1d33 Migration to TRON chain 2025-12-23 15:42:07 +01:00
bc6a56c129 Merge pull request 'Implemented cooldown before User is able to resend confirmation code for 2fa' (#128) from SEND012 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #128
2025-12-23 12:56:07 +00:00
Arseni
ec54579921 Implemented cooldown before User is able to resend confirmation code for 2fa 2025-12-23 14:56:47 +03:00
1ed76f7243 Merge pull request 'Fixed tokens revocation' (#127) from devid-122 into main
Some checks are pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline is running
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/frontend Pipeline is running
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #127
2025-12-22 20:25:03 +00:00
Stephan D
6527d183ec Fixed tokens revokation 2025-12-22 21:22:51 +01:00
41b0dec460 Merge pull request 'Fixes for Settings Page' (#123) from SEND011 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #123
Reviewed-by: tech <tech.sendico@proton.me>
2025-12-22 19:26:44 +00:00
Arseni
d26ba84094 Moved the AccountName widgets to pull providers from context 2025-12-22 21:38:26 +03:00
Arseni
4073c8819c Fixed imports 2025-12-22 21:12:21 +03:00
Arseni
47ada0691c Fixes for Settings Page 2025-12-22 21:09:58 +03:00
97c67670e5 Merge pull request 'added fix for active indexed tokens + improved data structure for wallet description' (#122) from quotes-118 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #122
2025-12-22 17:30:48 +00:00
Stephan D
dfad7fb335 added fix for active indexed tokens + improved data structure for wallet description 2025-12-22 18:30:15 +01:00
41abf723e6 Merge pull request 'multiquote service' (#117) from quotes-118 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #117
2025-12-17 20:56:28 +00:00
Stephan D
2d6586430f multiquote service 2025-12-17 21:56:07 +01:00
d649748f6f Merge pull request 'server endpoint' (#115) from quotes-115 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
Reviewed-on: #115
2025-12-17 17:15:40 +00:00
Stephan D
61177a4e30 server endpoint 2025-12-17 18:15:02 +01:00
c7b9b70d57 Merge pull request 'multiple quotes payment' (#114) from quotes-114 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #114
2025-12-17 15:53:29 +00:00
Stephan D
5030453807 multiple quotes payment 2025-12-17 16:53:03 +01:00
5565081b69 Merge pull request 'PostHog last fixes hopefully' (#109) from SEND006 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
Reviewed-on: #109
2025-12-17 12:22:33 +00:00
b216aa68b7 Merge pull request 'Empty state for Recipient Address Book' (#110) from SEND007 into main
Reviewed-on: #110
2025-12-17 11:48:07 +00:00
7ac1c519e3 Merge pull request 'Made clear massages for errors in recipient registration' (#111) from SEND008 into main
Some checks are pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline is running
ci/woodpecker/push/frontend Pipeline is running
ci/woodpecker/push/chain_gateway Pipeline was successful
Reviewed-on: #111
2025-12-17 11:13:16 +00:00
076b0c6434 Merge pull request 'Wallet update for correct name and symbol appearance' (#112) from SEND009 into main
Some checks failed
ci/woodpecker/push/bff Pipeline failed
ci/woodpecker/push/chain_gateway Pipeline is pending
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline failed
Reviewed-on: #112
2025-12-17 11:12:26 +00:00
Arseni
9a90e6a03b Wallet update for correct name and symbol appearance 2025-12-16 19:37:28 +03:00
Arseni
5218632c00 Made clear massages for errors in recipient registration 2025-12-16 18:42:57 +03:00
Arseni
a2c05745ad A 2025-12-16 18:21:49 +03:00
Arseni
82b2f88122 Changed the spelling of the word adress) 2025-12-12 19:39:36 +03:00
Arseni
28d74d058b Empty state for Recipient Adress Book 2025-12-12 19:29:10 +03:00
Arseni
6ee146b95a PostHog last fixes hopefully 2025-12-12 16:39:18 +03:00
67b52af150 Merge pull request 'fixed dropping of settlement mode' (#108) from settlement-106 into main
Some checks failed
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
Reviewed-on: #108
2025-12-12 13:19:29 +00:00
Stephan D
058a3fefaf fixed dropping of settlement mode 2025-12-12 14:19:09 +01:00
c8a97d940c Merge pull request 'quotation rate display' (#105) from fees-104 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline failed
ci/woodpecker/push/ledger Pipeline failed
Reviewed-on: #105
2025-12-12 12:46:21 +00:00
Stephan D
00045c1e65 quotation rate display 2025-12-12 13:45:58 +01:00
d64d7dab58 Merge pull request 'fixed quotation calculation logic' (#103) from fees-102 into main
Some checks failed
ci/woodpecker/push/chain_gateway Pipeline is pending
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/bff Pipeline failed
Reviewed-on: #103
2025-12-12 12:42:13 +00:00
Stephan D
4746a00eee fixed quotation calculation logic 2025-12-12 13:41:37 +01:00
3f8399d647 Merge pull request 'fixed fee polarity' (#101) from currency-100 into main
Some checks failed
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
Reviewed-on: #101
2025-12-12 12:21:19 +00:00
Stephan D
028b29fe08 fixed fee polarity 2025-12-12 13:21:00 +01:00
cb3f59a9d5 Merge pull request 'fixed duplicated ISO codes parsing' (#99) from currency-99 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #99
2025-12-12 10:42:07 +00:00
Stephan D
2b8d02d95c fixed duplicated ISO codes parsing 2025-12-12 11:41:45 +01:00
d90d8cda11 Merge pull request 'fx/ingestor currencies map fixed' (#98) from currencies-97 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline failed
ci/woodpecker/push/notification Pipeline failed
Reviewed-on: #98
2025-12-12 10:05:52 +00:00
Stephan D
17333df7af fx/ingestor currencies map fixed 2025-12-12 11:05:12 +01:00
681d53e856 Merge pull request 'Fixed http client' (#96) from client-95 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #96
2025-12-12 00:53:59 +00:00
Stephan D
dc608fd257 Fixed http client 2025-12-12 01:53:34 +01:00
cd2efdc2f3 Merge pull request 'improved fx/ingestor logging' (#93) from logging-92 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline failed
ci/woodpecker/push/notification Pipeline was successful
Reviewed-on: #93
2025-12-12 00:07:25 +00:00
Stephan D
fd47867101 improved fx/ingestor logging 2025-12-12 01:07:03 +01:00
2ca1a6956c Merge pull request 'fx/oracle logging' (#92) from logging-90 into main
Some checks failed
ci/woodpecker/push/chain_gateway Pipeline is pending
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/bff Pipeline failed
ci/woodpecker/push/billing_fees Pipeline failed
Reviewed-on: #92
2025-12-12 00:05:13 +00:00
Stephan D
a5ad4f4c3c fx/oracle logging 2025-12-12 00:44:04 +01:00
8b202e0c60 Merge pull request 'fixed currency validation logic' (#89) from currency-88 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #89
2025-12-11 22:55:50 +00:00
Stephan D
4626d0a1a7 fixed currency validation logic 2025-12-11 23:55:04 +01:00
da72121109 Merge pull request 'ledger account reference removed' (#87) from fees-86 into main
Some checks failed
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
Reviewed-on: #87
2025-12-11 22:32:26 +00:00
Stephan D
5bebadf17c ledger account reference removed 2025-12-11 23:30:42 +01:00
1bab0b14ef Merge pull request 'fixed currency pair validation' (#85) from currency-84 into main
Some checks failed
ci/woodpecker/push/chain_gateway Pipeline is pending
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/bff Pipeline failed
Reviewed-on: #85
2025-12-11 22:27:42 +00:00
Stephan D
39f323d050 fixed currency pair validation 2025-12-11 23:27:15 +01:00
7cd9e14618 Merge pull request 'logging-84' (#83) from logging-84 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #83
2025-12-11 21:37:04 +00:00
Stephan D
b77d2c16ab improved logging 2025-12-11 22:25:51 +01:00
Stephan D
324f150950 improved logging 2025-12-11 22:25:04 +01:00
dd6bcf843c Merge pull request 'fixed payment orchestrator address' (#81) from connectivity-81 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline failed
ci/woodpecker/push/mntx_gateway Pipeline failed
ci/woodpecker/push/notification Pipeline failed
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #81
2025-12-11 20:53:04 +00:00
Stephan D
874cc4971b fixed payment orchestrator address 2025-12-11 21:52:37 +01:00
bfe4695b2d Merge pull request 'config fix' (#80) from discovery-79 into main
Some checks failed
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
Reviewed-on: #80
2025-12-11 20:39:07 +00:00
Stephan D
99161c8e7d config fix 2025-12-11 21:38:32 +01:00
6901791dd2 Merge pull request 'default currency resolver' (#78) from currency-76 into main
Some checks failed
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
Reviewed-on: #78
2025-12-11 20:24:10 +00:00
Stephan D
acb3d14b47 default currency resolver 2025-12-11 21:23:35 +01:00
aa5f7e271e Merge pull request 'fix currencies validation' (#76) from currencies-75 into main
Some checks failed
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
Reviewed-on: #76
2025-12-11 20:06:22 +00:00
Stephan D
0a01995f53 fix currencies validation 2025-12-11 21:05:43 +01:00
97f71d125e Merge pull request 'removed deprecation warnings' (#71) from deprecation-70 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
Reviewed-on: #71
2025-12-11 10:23:12 +00:00
Stephan D
8db2f3926c deprecation fixed 2025-12-11 11:22:51 +01:00
Stephan D
2b68b59eca removed deprecation warnings 2025-12-11 11:11:54 +01:00
d07e64fc4f Merge pull request 'fix fx/oracle compilation' (#68) from bug-66 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline failed
ci/woodpecker/push/mntx_gateway Pipeline failed
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #68
2025-12-11 09:36:50 +00:00
Stephan D
8e40e6247b fix fx/oracle compilation 2025-12-11 10:36:31 +01:00
779cb0ead9 Merge pull request 'fix' (#65) from bug-64 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #65
2025-12-11 00:45:07 +00:00
Stephan D
2e0057f839 fix 2025-12-11 01:44:40 +01:00
25080ae168 Merge pull request 'fix' (#63) from bug-62 into main
Some checks failed
ci/woodpecker/push/bff Pipeline failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
Reviewed-on: #63
2025-12-11 00:31:19 +00:00
Stephan D
e6b001dc61 fix 2025-12-11 01:30:28 +01:00
97d1470515 Merge pull request '+ quotation provider' (#60) from quote-front-59 into main
Some checks failed
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
Reviewed-on: #60
2025-12-11 00:13:35 +00:00
Stephan D
a4481fb63d + quotation provider 2025-12-11 01:13:13 +01:00
bdf766075e Merge pull request 'payment rails' (#58) from payment-service-52 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline failed
Reviewed-on: #58
2025-12-10 17:50:38 +00:00
Stephan D
47899e25d4 payment rails 2025-12-10 18:40:55 +01:00
4ec934c96b Merge pull request 'fixed CORS wildcard' (#55) from CORS-#54 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/ledger Pipeline failed
ci/woodpecker/push/mntx_gateway Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline failed
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline failed
Reviewed-on: #55
2025-12-09 19:00:01 +00:00
Stephan D
19df740550 fixed CORS wildcard 2025-12-09 19:59:33 +01:00
1079ad7d0a Merge pull request 'Organizations now load only once' (#38) from SEND002 into main
Some checks failed
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline failed
ci/woodpecker/push/bff Pipeline failed
Reviewed-on: #38
2025-12-09 18:53:13 +00:00
81d2db394b Merge pull request 'removed auto-generated code' (#51) from interface-#50 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #51
2025-12-09 17:36:05 +00:00
Stephan D
8d6a302cb8 removed auto-generated code 2025-12-09 18:35:42 +01:00
0e48d2a318 Merge pull request 'double-sided quotation + fixed tests' (#49) from quote-#45 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #49
2025-12-09 16:46:02 +00:00
Stephan D
32653e11fc double-sided quotation + fixed tests 2025-12-09 17:45:29 +01:00
a24ead2c36 Merge pull request 'quotation bff' (#46) from quote-#45 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline failed
Reviewed-on: #46
2025-12-09 15:30:46 +00:00
Stephan D
ce59cb1b26 quotation bff 2025-12-09 16:29:29 +01:00
cecaebfc5e Merge pull request 'Minor fixes for build to complete' (#44) from SEND001 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #44
2025-12-09 13:48:07 +00:00
Arseni
660f689a7a Current org now sets after list gets to the state of the provider 2025-12-09 16:15:36 +03:00
e16f11d48a Merge branch 'main' into SEND001 2025-12-09 12:31:47 +00:00
Arseni
0804ad71f7 Minor fixes for build to complete 2025-12-09 15:30:46 +03:00
7a2f921de9 Merge pull request 'version bump + CBR fx ingestor' (#42) from cbr-#41 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #42
2025-12-08 18:54:03 +00:00
Stephan D
999f0684cb version bump + CBR fx ingestor 2025-12-08 19:52:03 +01:00
602b77ddc7 Merge pull request 'Navigation now flows entirely through go_router' (#35) from SEND001 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #35
2025-12-08 17:56:33 +00:00
Arseni
8115abb569 Organizations now load only once 2025-12-08 19:10:33 +03:00
Arseni
64ad8c8b38 Navigation now flows entirely through go_router 2025-12-08 17:40:25 +03:00
f478219990 Merge pull request 'Top Up Balance logic and Added fixes for routing' (#31) from SEND001 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #31
2025-12-06 23:35:53 +00:00
Arseni
bf39b1d401 Top Up Balance logic and Added fixes for routing 2025-12-05 20:29:43 +03:00
f7bf3138ac Merge pull request 'balance cache' (#30) from balance-cache-#29 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
Reviewed-on: #30
2025-12-05 09:55:29 +00:00
Stephan D
7cb747f9a9 balance cache 2025-12-05 10:55:01 +01:00
f2658aea44 Merge pull request 'address book complete' (#28) from address-book-#16 into main
Some checks failed
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
Reviewed-on: #28
2025-12-05 09:32:54 +00:00
Stephan D
5e49ee3244 address book complete 2025-12-05 10:27:55 +01:00
1073be187f Merge pull request 'fixed recipient storing problem' (#27) from address-book-#16 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #27
2025-12-05 08:38:31 +00:00
Stephan D
e854963fa6 fixed recipient storing problem 2025-12-05 09:37:51 +01:00
e5f283432b Merge pull request 'docker conflict resolved' (#26) from address-book-#16 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
Reviewed-on: #26
2025-12-05 05:01:55 +00:00
Stephan D
d62a3413b2 docker conflict resolved 2025-12-05 06:01:23 +01:00
f720ba9bdf Merge pull request 'address-book-#16' (#25) from address-book-#16 into main
Some checks failed
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/ledger Pipeline failed
ci/woodpecker/push/mntx_gateway Pipeline failed
ci/woodpecker/push/chain_gateway Pipeline failed
Reviewed-on: #25
2025-12-05 04:51:04 +00:00
Stephan D
98f254e34b docker conflict resolved 2025-12-05 05:50:34 +01:00
Stephan D
980bb96c74 relaxed healthcheck 2025-12-05 05:43:08 +01:00
4bb18f0210 Merge pull request 'fixed payment methods serialization deserialization' (#24) from address-book-#16 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline failed
ci/woodpecker/push/notification Pipeline failed
Reviewed-on: #24
2025-12-05 04:17:45 +00:00
Stephan D
574b40fe9f fixed payment methods serialization deserialization 2025-12-05 05:17:14 +01:00
a3a807e625 Merge pull request 'fixed port + recipient storing' (#23) from address-book-#16 into main
Some checks failed
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline failed
ci/woodpecker/push/ledger Pipeline failed
Reviewed-on: #23
2025-12-05 03:49:13 +00:00
Stephan D
3b047af7ca fixed port + recipient storing 2025-12-05 04:48:50 +01:00
36cc46577c Merge pull request 'recipient saving' (#22) from address-book-#16 into main
Some checks failed
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
Reviewed-on: #22
2025-12-05 03:36:47 +00:00
Stephan D
e1da16448b recipient saving 2025-12-05 04:34:11 +01:00
fed6f39de6 Merge pull request 'address-book-#16' (#21) from address-book-#16 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline failed
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #21
2025-12-05 02:41:11 +00:00
Stephan D
85fb567ed9 rewored monetix gateawy to port 8084 2025-12-05 03:39:59 +01:00
Stephan D
fd07c10cba version bump 2025-12-05 03:31:33 +01:00
Stephan D
c44edc85fa fixed db installation 2025-12-05 03:25:52 +01:00
57a48fe2a3 Merge pull request 'migration to address book service' (#20) from address-book-#16 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline failed
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #20
2025-12-05 02:03:11 +00:00
Stephan D
2b2a8afc2f migration to address book service 2025-12-05 03:02:43 +01:00
d431317a50 Merge pull request 'migration to address book service' (#19) from address-book-#16 into main
Some checks failed
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/chain_gateway Pipeline failed
Reviewed-on: #19
2025-12-05 01:53:44 +00:00
Stephan D
b4c696f1ef migration to address book service 2025-12-05 02:52:02 +01:00
4d03a6ead8 Merge pull request 'address-book-#16' (#18) from address-book-#16 into main
Some checks failed
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
Reviewed-on: #18
2025-12-05 01:32:54 +00:00
Stephan D
2fe5151650 migration to address book service 2025-12-05 02:32:20 +01:00
Stephan D
2754a7aa13 migration to address book service 2025-12-05 02:30:49 +01:00
Stephan D
f71cc76f64 temp build 2025-12-05 01:32:41 +01:00
082d782a80 Merge pull request 'Missing policies' (#15) from policies-#14 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/mntx_gateway Pipeline failed
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
Reviewed-on: #15
2025-12-04 21:27:48 +00:00
Stephan D
18f8f3c476 Missing policies 2025-12-04 22:27:16 +01:00
659b90b6a5 Merge pull request '+ missing localizatoin +permissions fix' (#13) from recipients-#12 into main
Some checks failed
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/chain_gateway Pipeline failed
Reviewed-on: #13
2025-12-04 21:18:41 +00:00
Stephan D
84318883d2 + missing localizatoin +permissions fix 2025-12-04 22:18:09 +01:00
668ade2014 Merge pull request 'mntx-#10' (#11) from mntx-#10 into main
Some checks failed
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/ledger Pipeline failed
Reviewed-on: #11
2025-12-04 20:51:30 +00:00
Stephan D
43c4866ad7 +logging 2025-12-04 21:50:49 +01:00
Stephan D
396a0c0c88 monetix gateway 2025-12-04 21:16:15 +01:00
f439f53524 Merge pull request 'icons update' (#9) from icon-#3 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #9
2025-12-04 15:40:56 +00:00
Stephan D
2052602050 icons update 2025-12-04 16:40:26 +01:00
Stephan D
bf85ca062c restucturization of recipients payment methods
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
2025-12-04 14:42:25 +01:00
Arseni
3b04753f4e Revert "Merge branch 'devKA' into devka (resolve conflicts)"
Some checks are pending
ci/woodpecker/push/bump_version Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/frontend Pipeline is running
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline is running
This reverts commit 5f4184760d, reversing
changes made to 5e1da9617f.

Reverting changes on main
2025-12-04 15:38:01 +03:00
Arseni
5f4184760d Merge branch 'devKA' into devka (resolve conflicts)
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version unknown status
2025-12-04 14:08:32 +03:00
Stephan D
5e1da9617f +address book service
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-12-01 21:20:10 +01:00
Arseni
9c16e27645 Fixed issue with wallet form feild and made page selecor in dashboard into a router 2025-11-27 18:07:28 +03:00
Stephan D
c4d34c5663 added wallet management localizations
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-26 23:25:31 +01:00
Stephan D
34420ca2fb +gas estimation
Some checks failed
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline failed
ci/woodpecker/push/bump_version unknown status
ci/woodpecker/push/bff Pipeline failed
2025-11-26 23:19:29 +01:00
Stephan D
d16703197d onchain balance getter implementation
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-26 22:25:15 +01:00
Stephan D
35897f9aa1 impreoved commands logging
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-26 21:45:38 +01:00
Stephan D
f59ee55084 removed untranslated.txt from repo
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-26 19:36:47 +01:00
Stephan D
8bf86c5c93 removed obsolete files
Some checks failed
ci/woodpecker/push/bump_version unknown status
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/chain_gateway Pipeline is pending
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/bff Pipeline failed
2025-11-26 19:35:35 +01:00
Stephan D
5e8ff2adb7 removed CORS restrictions
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/bump_version unknown status
ci/woodpecker/push/payments_orchestrator Pipeline failed
2025-11-26 19:02:30 +01:00
Stephan D
da57b1d2e0 fixed providers initialization
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-26 18:17:30 +01:00
2ef9ac24a1 Merge pull request 'Added Localizations and ran small fixes' (#6) from devKA into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
Reviewed-on: #6
2025-11-26 14:00:56 +00:00
Stephan D
44446c6ad4 conflicts resolution 2025-11-26 15:00:21 +01:00
Arseni
357af99564 Added account permissions and ui for recipient 2025-11-26 13:03:52 +03:00
Stephan D
48ccbb1c82 implemented backend wallet service connection
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-26 00:48:00 +01:00
Stephan D
68f0a1048f implemented backend wallets/ledger accounts listing 2025-11-25 23:38:10 +01:00
Stephan D
be913bf96c + logout connected 2025-11-25 21:37:22 +01:00
Stephan D
8e1d4bef59 fixed account provider dependencies
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline failed
ci/woodpecker/push/payments_orchestrator Pipeline failed
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/bump_version unknown status
2025-11-25 19:25:07 +01:00
Stephan D
c6da138184 fixed account provider dependencies
Some checks failed
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/bump_version unknown status
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/frontend Pipeline failed
2025-11-25 19:04:39 +01:00
Stephan D
d78619bccf improved logging
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-25 18:30:53 +01:00
Stephan D
85b780b57e check other approach
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-25 17:45:47 +01:00
Stephan D
1f31fedc3a excessive provider removed
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-25 12:40:39 +01:00
Stephan D
bdf3a01f80 fixed paths
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-25 11:57:27 +01:00
Stephan D
d126d5d5de fixed service name for verfication
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-25 11:06:40 +01:00
Arseni
fcb5ab4f2c Added Localizations and ran small fixes 2025-11-25 08:20:09 +03:00
Stephan D
26a1e284b2 Rewired login confirmation
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-25 00:46:11 +01:00
Stephan D
fc0600d6c4 fix
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-24 23:16:13 +01:00
Stephan D
b855404999 new message type
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version unknown status
2025-11-24 21:49:02 +01:00
Stephan D
e3a8fb4f2d mail templates
Some checks failed
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline failed
ci/woodpecker/push/bump_version unknown status
ci/woodpecker/push/chain_gateway Pipeline failed
2025-11-24 21:42:06 +01:00
Stephan D
d65e442cb6 + token verification
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version unknown status
2025-11-24 20:53:42 +01:00
Stephan D
b4f6f63871 fixed mail server connection string
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-24 19:44:55 +01:00
Stephan D
803683be7c fixed change order
Some checks failed
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline failed
ci/woodpecker/push/bump_version unknown status
ci/woodpecker/push/frontend Pipeline failed
2025-11-24 19:32:04 +01:00
Stephan D
72271cfc9a migration to replicaset connection
Some checks failed
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/bump_version unknown status
ci/woodpecker/push/frontend Pipeline failed
2025-11-24 19:10:07 +01:00
Stephan D
cd79355e69 fixed org ref setting
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-24 15:18:31 +01:00
Stephan D
3f84f8c609 fixed org creation org referencing
Some checks failed
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline failed
ci/woodpecker/push/bump_version unknown status
ci/woodpecker/push/bff Pipeline failed
2025-11-24 15:11:47 +01:00
Stephan D
ae15e1887b better error checks
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/bump_version unknown status
ci/woodpecker/push/chain_gateway Pipeline failed
2025-11-24 15:03:10 +01:00
Stephan D
8a41785b1d better logging in the pkg
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-24 14:15:37 +01:00
Stephan D
56abc10dce version bump + loggins
Some checks failed
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/bump_version unknown status
ci/woodpecker/push/frontend Pipeline failed
2025-11-24 13:57:50 +01:00
d8a3a5550d Merge pull request 'Multiple Wallet support, history of each wallet and updated payment page' (#5) from devKA into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
Reviewed-on: #5
2025-11-23 14:52:06 +00:00
Stephan D
72d8da1fe8 removed dev file 2025-11-23 15:50:46 +01:00
Stephan D
1fcd77cd95 fixes 2025-11-23 15:49:24 +01:00
Stephan D
f6a6be13d1 merge fixes 2025-11-23 15:45:10 +01:00
Stephan D
0b0d329b9b build script update
Some checks failed
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/bump_version unknown status
ci/woodpecker/push/frontend Pipeline failed
2025-11-23 15:37:45 +01:00
Stephan D
d00d9275fe prod conf update
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-21 22:56:36 +01:00
Arseni
775312d174 Fixed navigation 2025-11-21 21:09:32 +03:00
Stephan D
4d7827db61 prod setting for frontend
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-21 18:05:01 +01:00
Arseni
acbab71a57 Multiple Wallet support, history of each wallet and updated payment page 2025-11-21 19:25:37 +03:00
Arseni
87636a7ec3 Multiple Wallet support, history of each wallet and updated payment page 2025-11-21 19:22:23 +03:00
Stephan D
e1e4c580e8 New code verification service
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-21 16:41:41 +01:00
Stephan D
ef5b3dc1a7 extended message set
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-20 00:47:14 +01:00
Stephan D
36d1a94cf6 + call request
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-19 22:19:27 +01:00
Stephan D
56d6c8caa6 fixed requests filtration
Some checks failed
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/bump_version unknown status
2025-11-19 22:04:27 +01:00
Stephan D
29f5a56f21 fixed notifications dispatch
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-19 20:15:36 +01:00
Stephan D
e08eb742e4 + contact requests
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-19 14:42:38 +01:00
Stephan D
717dafc673 better message formatting
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-19 13:54:25 +01:00
Stephan D
62956b06ca better logging
Some checks failed
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/bump_version unknown status
ci/woodpecker/push/frontend Pipeline failed
2025-11-19 13:32:40 +01:00
Stephan D
8710d7da53 cleanup
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/bump_version unknown status
ci/woodpecker/push/payments_orchestrator Pipeline was successful
2025-11-19 12:47:45 +01:00
Stephan D
26a849e582 version bump
Some checks failed
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline failed
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/bump_version unknown status
ci/woodpecker/push/frontend Pipeline failed
2025-11-19 12:34:44 +01:00
Stephan D
796e7b63b9 Config fix
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-18 19:31:08 +01:00
Stephan D
c3a4a3cc1b Config fix
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline is running
ci/woodpecker/push/bff Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/frontend Pipeline is running
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/bump_version unknown status
ci/woodpecker/push/fx_ingestor Pipeline failed
2025-11-18 19:19:05 +01:00
Stephan D
020a40b90c Config fix
Some checks failed
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/bump_version unknown status
ci/woodpecker/push/fx_oracle Pipeline failed
2025-11-18 18:52:23 +01:00
Stephan D
515887d7f8 config fix
Some checks failed
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline failed
ci/woodpecker/push/bump_version unknown status
ci/woodpecker/push/frontend Pipeline failed
2025-11-18 18:40:41 +01:00
Stephan D
71a67e1f6d removed trash
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-18 17:33:01 +01:00
Stephan D
c5cdb7d2ae +caddy proxy fix +version bump fix 2025-11-18 17:32:23 +01:00
Stephan D
b12dbf07ea proxy app config fix
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-18 10:33:09 +01:00
Stephan D
c8579a14f3 Caddy reconfigured
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline failed
ci/woodpecker/push/frontend Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline failed
ci/woodpecker/push/notification Pipeline failed
ci/woodpecker/push/payments_orchestrator Pipeline failed
ci/woodpecker/push/bump_version unknown status
2025-11-18 02:56:57 +01:00
Stephan D
e2e77fe409 +www site to cors
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/bump_version unknown status
ci/woodpecker/push/frontend Pipeline failed
2025-11-18 02:43:09 +01:00
Stephan D
920a7fc90a extended logging 2025-11-18 02:39:25 +01:00
Stephan D
848ff556d2 version bump 2025-11-18 02:39:17 +01:00
Stephan D
df81a93838 changed CORS permissions
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/bump_version unknown status
ci/woodpecker/push/frontend Pipeline failed
2025-11-18 02:25:50 +01:00
Stephan D
e1f6f10114 health check fix
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-18 00:35:55 +01:00
Stephan D
922dad3dcd removed obsolete errors
Some checks failed
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/bump_version unknown status
ci/woodpecker/push/frontend Pipeline failed
2025-11-18 00:20:28 +01:00
Stephan D
363e9afc0a removed obsolete errors 2025-11-18 00:20:25 +01:00
Stephan D
ebb40c8e9b fixed chain address
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-17 23:40:12 +01:00
Stephan D
9dbf77a9a8 +notification from site +version bump fix
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-17 22:20:17 +01:00
Stephan D
c6a56071b5 +signup +login
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-17 20:16:45 +01:00
Stephan D
1ab7f2e7d3 +signup +email availability check
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-17 18:00:38 +01:00
Stephan D
4c64a8d6e6 version bump
Some checks failed
ci/woodpecker/push/bff Pipeline failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/bump_version unknown status
ci/woodpecker/push/payments_orchestrator Pipeline was successful
2025-11-15 01:18:50 +01:00
Stephan D
4c3bdc2ca6 build: +new fix
Some checks failed
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline failed
ci/woodpecker/push/bump_version unknown status
ci/woodpecker/push/ledger Pipeline failed
2025-11-15 01:06:23 +01:00
Stephan D
0d18da6a18 build: + frontend dependency 2025-11-15 01:05:20 +01:00
Stephan D
02d49f2502 front: fix proxy config 2025-11-15 00:50:40 +01:00
Stephan D
9a891fd523 deps version bump + frontend
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-14 16:35:17 +01:00
Stephan D
975496ecbe deps version bump
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-14 15:46:24 +01:00
Stephan D
38158bec4d + version bump
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline failed
ci/woodpecker/push/notification Pipeline failed
ci/woodpecker/push/bump_version unknown status
2025-11-14 15:20:12 +01:00
Stephan D
cb69757aea + version bump
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
2025-11-14 12:53:51 +01:00
Stephan D
c9b4bf7ceb + version bump
Some checks failed
ci/woodpecker/push/bff Pipeline failed
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline failed
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/ledger Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline failed
ci/woodpecker/push/payments_orchestrator Pipeline failed
ci/woodpecker/push/bump_version unknown status
2025-11-14 12:44:51 +01:00
39e4aa5cb3 Merge pull request 'devKA' (#4) from devKA into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
Reviewed-on: #4
2025-11-14 04:09:19 +00:00
Arseni
aac6cd2b9b deletes ds_store files 2025-11-13 15:07:43 +03:00
Arseni
ddb54ddfdc Frontend first draft 2025-11-13 15:06:15 +03:00
Stephan D
96bb94d805 gitignore fix + missing storage management
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
2025-11-11 22:41:17 +01:00
Stephan D
05652bdb41 +bff
Some checks failed
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/bff Pipeline failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline failed
ci/woodpecker/push/fx/1 Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline was successful
ci/woodpecker/push/nats Pipeline failed
ci/woodpecker/push/ledger Pipeline failed
2025-11-11 22:26:09 +01:00
Stephan D
45dcf1714f + missing file
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline failed
ci/woodpecker/push/fx/1 Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline failed
2025-11-11 22:04:01 +01:00
Stephan D
da600aa63d + chain gateway
Some checks failed
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/fx/1 Pipeline failed
2025-11-11 21:51:52 +01:00
Stephan D
92064dfbb4 fixed notification deps
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/notification Pipeline failed
ci/woodpecker/push/payments_orchestrator Pipeline was successful
2025-11-11 20:36:34 +01:00
Stephan D
fd56d3e8c4 versions bump
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline failed
ci/woodpecker/push/payments_orchestrator Pipeline was successful
2025-11-11 20:33:56 +01:00
Stephan D
43a18e37a0 nootification build
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline failed
ci/woodpecker/push/payments_orchestrator Pipeline was successful
2025-11-11 18:59:47 +01:00
Arseni
e47f343afb первый коммит 2025-11-11 18:24:58 +03:00
Stephan D
6f7ea2bf98 payment orchestrator build
All checks were successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
2025-11-11 16:20:34 +01:00
Stephan D
40a3460e6d chain gateway build fix
All checks were successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
2025-11-11 13:56:21 +01:00
Stephan D
052cfcea4c chain gateway build fix
All checks were successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline was successful
2025-11-11 13:09:33 +01:00
Stephan D
4cf7bc65ce chain gateway build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
2025-11-11 09:42:53 +01:00
Stephan D
4dfe6f8eac chain gateway build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
2025-11-11 09:26:00 +01:00
Stephan D
881ebaff5f chain gateway build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
2025-11-11 09:15:23 +01:00
Stephan D
d723047dd4 chain gateway build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-11 00:57:28 +01:00
Stephan D
a6da4d08bc chain gateway build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline failed
ci/woodpecker/push/fees Pipeline failed
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-11 00:35:23 +01:00
Stephan D
c17af597d2 chain gateway build
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline failed
ci/woodpecker/push/fees Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
2025-11-10 17:46:12 +01:00
Stephan D
b74ab81192 billing fees build
All checks were successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fees Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline was successful
2025-11-10 15:13:25 +01:00
Stephan D
751045fcc0 fx build fix
All checks were successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline was successful
2025-11-09 02:57:22 +01:00
Stephan D
54de5cf9d8 fx build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-09 02:52:09 +01:00
Stephan D
7df47cdc8e fx build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline is running
2025-11-09 00:44:21 +01:00
Stephan D
64ef4fe0fe fx build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline failed
2025-11-08 11:38:24 +01:00
Stephan D
88b2b63759 fx build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-08 11:23:49 +01:00
Stephan D
8810bc8783 fx build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-08 11:19:18 +01:00
Stephan D
be51fb7f8b fx build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
2025-11-08 03:45:32 +01:00
Stephan D
6f3d2b6769 fx build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-08 03:42:23 +01:00
Stephan D
0f8737a906 fx build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-08 03:40:49 +01:00
Stephan D
5c73106044 fx build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-08 03:34:12 +01:00
Stephan D
b6c795a0c8 fx build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-08 03:30:45 +01:00
Stephan D
677fb51a67 fx build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-08 03:27:14 +01:00
Stephan D
7b3ae24504 fx build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-08 03:21:57 +01:00
Stephan D
2f4938f304 fx build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-08 03:19:33 +01:00
Stephan D
1c10790149 fx build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-08 03:09:31 +01:00
Stephan D
36f7b785dd fx build fix
Some checks failed
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-08 03:07:40 +01:00
Stephan D
e2c370c00a fx build fix
Some checks failed
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline failed
2025-11-08 03:06:35 +01:00
Stephan D
5602af501f fx build fix
Some checks failed
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/fx/1 Pipeline failed
2025-11-08 03:05:34 +01:00
Stephan D
74b8e02c3a fx build fix
Some checks failed
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-08 03:02:21 +01:00
Stephan D
8759b969b3 fx build fix
Some checks failed
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-08 03:00:55 +01:00
Stephan D
618f7286fe fx build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-08 02:58:43 +01:00
Stephan D
f9b7114a6d fx build fix
Some checks failed
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/nats Pipeline failed
ci/woodpecker/push/fx/2 Pipeline failed
2025-11-08 02:58:00 +01:00
Stephan D
d367dddbbd fx build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
2025-11-08 00:40:01 +01:00
Stephan D
49b86efecb fx build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
2025-11-08 00:30:29 +01:00
Stephan D
590fad0071 fx build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-07 23:55:41 +01:00
Stephan D
2ee17b0c46 fx build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-07 23:50:48 +01:00
Stephan D
0c0eeb27f8 build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
2025-11-07 23:04:57 +01:00
Stephan D
0e40af7559 build fix
Some checks failed
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-07 22:58:59 +01:00
Stephan D
1c4856f7cc build fix
Some checks failed
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-07 21:53:39 +01:00
Stephan D
19eadd1537 build fix
Some checks failed
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-07 21:34:48 +01:00
Stephan D
f102d69628 build fix
Some checks failed
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-07 20:49:19 +01:00
Stephan D
a5900232fc build fix
Some checks failed
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-07 20:47:40 +01:00
Stephan D
aca5a61cc8 build fix
Some checks failed
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-07 20:45:45 +01:00
Stephan D
cf98875299 build fix
Some checks failed
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-07 20:39:50 +01:00
Stephan D
6598ce5d3a build fix
Some checks failed
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-07 20:37:46 +01:00
Stephan D
2e23e647f8 build fix
Some checks failed
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-07 20:34:28 +01:00
Stephan D
36f48331b4 build fix
Some checks failed
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
2025-11-07 20:18:16 +01:00
Stephan D
ec3019c462 + fx
Some checks failed
ci/woodpecker/push/fx_ingestor Pipeline failed
ci/woodpecker/push/fx_oracle Pipeline failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
2025-11-07 20:13:41 +01:00
Stephan D
62a6631b9a service backend
All checks were successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
2025-11-07 18:35:26 +01:00
Stephan D
20e8f9acc4 fixed nats healthcheck
All checks were successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
2025-11-07 16:31:50 +01:00
Stephan D
77aaea8b3d fixed nats healthcheck
All checks were successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
2025-11-07 16:19:32 +01:00
Stephan D
49cdd8cbee fixed nats healthcheck
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/nats Pipeline failed
2025-11-07 16:07:31 +01:00
Stephan D
8b427e42c8 fixed nats healthcheck
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/nats Pipeline failed
2025-11-07 16:02:06 +01:00
Stephan D
d1150dbf9d fixed nats healthcheck
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/nats Pipeline failed
2025-11-07 16:00:39 +01:00
Stephan D
b79a6116d1 fixed nats healthcheck
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/nats Pipeline failed
2025-11-07 15:57:10 +01:00
Stephan D
7bcc24a690 +project names
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/nats Pipeline failed
2025-11-07 14:59:22 +01:00
Stephan D
dce6e2f618 fixed nats copy
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/nats Pipeline failed
2025-11-07 14:53:29 +01:00
Stephan D
f69aeacae3 fixed pbm network
Some checks failed
ci/woodpecker/push/nats Pipeline failed
ci/woodpecker/push/db Pipeline was successful
2025-11-07 14:49:31 +01:00
Stephan D
e8f6f28880 +NATS
Some checks failed
ci/woodpecker/push/nats Pipeline failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 14:45:05 +01:00
Stephan D
677017334a added pbm credentials insallation
All checks were successful
ci/woodpecker/push/db Pipeline was successful
2025-11-07 13:05:28 +01:00
Stephan D
cc92b2b1dd force recreate
All checks were successful
ci/woodpecker/push/db Pipeline was successful
2025-11-07 12:46:10 +01:00
Stephan D
0dfe32161a fixed password preparation
All checks were successful
ci/woodpecker/push/db Pipeline was successful
2025-11-07 12:41:22 +01:00
Stephan D
601fcebac5 removed manual permissions maangement
All checks were successful
ci/woodpecker/push/db Pipeline was successful
2025-11-07 12:02:58 +01:00
Stephan D
ae310632a1 fixed secrets path
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 11:36:54 +01:00
Stephan D
d17996973e missing dep
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 11:33:44 +01:00
Stephan D
ca76eb5bf9 vault app_role secrets pass
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 11:31:32 +01:00
Stephan D
0bb32ccabd vault app_role secrets pass
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 11:15:57 +01:00
Stephan D
385c98939a removed debug output 2025-11-07 11:03:18 +01:00
Stephan D
b9d356669a db deployment trace
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 10:58:09 +01:00
Stephan D
e70fc9567a db deployment trace
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 10:49:22 +01:00
Stephan D
5b58c07164 db deployment trace
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 10:43:39 +01:00
Stephan D
44b143e4c3 db deployment trace
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 10:35:48 +01:00
Stephan D
3b01d53c50 db deployment trace
All checks were successful
ci/woodpecker/push/db Pipeline was successful
2025-11-07 10:20:51 +01:00
Stephan D
9cd65b1eb1 removed db lock
All checks were successful
ci/woodpecker/push/db Pipeline was successful
2025-11-07 10:02:46 +01:00
Stephan D
9f5c1147dc fixed db lock
All checks were successful
ci/woodpecker/push/db Pipeline was successful
2025-11-07 03:16:20 +01:00
Stephan D
2cb14a57c4 fixed db lock
All checks were successful
ci/woodpecker/push/db Pipeline was successful
2025-11-07 03:13:08 +01:00
Stephan D
3f0275d006 fixed db lock
All checks were successful
ci/woodpecker/push/db Pipeline was successful
2025-11-07 03:06:45 +01:00
Stephan D
08f71ff583 fixed db lock
All checks were successful
ci/woodpecker/push/db Pipeline was successful
2025-11-07 03:00:39 +01:00
Stephan D
d68154f8ec fixed db lock
All checks were successful
ci/woodpecker/push/db Pipeline was successful
2025-11-07 02:57:23 +01:00
Stephan D
df4af6c1e8 version bump
All checks were successful
ci/woodpecker/push/db Pipeline was successful
2025-11-07 02:49:31 +01:00
Stephan D
dacd8a2115 fixed docker login
All checks were successful
ci/woodpecker/push/db Pipeline was successful
2025-11-07 02:38:09 +01:00
Stephan D
c8494da642 fixed env vars delivery
All checks were successful
ci/woodpecker/push/db Pipeline was successful
2025-11-07 02:30:47 +01:00
Stephan D
2335d2378f fixed env vars delivery
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 02:29:23 +01:00
Stephan D
eef4f01ea0 fixed env vars delivery
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 02:27:28 +01:00
Stephan D
5c5a7e14a1 fixed deployment docker file target
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 02:25:26 +01:00
Stephan D
3d7f5c4261 Added env to the remote mkdir -p list
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 02:18:28 +01:00
Stephan D
fcf4ad4d73 converted key to b64
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 02:11:23 +01:00
Stephan D
ecd43cb3cc converted key to b64
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 02:09:49 +01:00
Stephan D
86fcb9d82f fixed multiline secret handling
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 02:04:12 +01:00
Stephan D
b8c8ce7019 fixed path generation
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 01:52:38 +01:00
Stephan D
a2975ba5fb added missing bash
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 01:47:56 +01:00
Stephan D
6ea47a9c68 fixed script start
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 01:46:54 +01:00
Stephan D
035f6f74bc ensure folder target folder exists
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 01:44:39 +01:00
Stephan D
8cea7f005b reduced mongo image size
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 01:43:08 +01:00
Stephan D
2954dcde7b fixed docker registry access
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 01:32:31 +01:00
Stephan D
dbc77a7156 fixed vault paths
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 01:28:21 +01:00
Stephan D
29577230d2 migration to db deployment helper
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 01:27:19 +01:00
Stephan D
8de7c57c41 fixed package installation
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 01:21:17 +01:00
Stephan D
ed219040a9 fixed ssh_key access path
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 01:19:55 +01:00
Stephan D
34b3b089fc fixed registry access path
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 01:18:30 +01:00
Stephan D
7ad3939d77 + wp check
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 01:15:50 +01:00
Stephan D
bf3ba978d6 fixed secret id
Some checks failed
ci/woodpecker/push/db Pipeline failed
2025-11-07 01:09:45 +01:00
Stephan D
24bd7c82eb Wrapped the skopeo copy and skopeo inspect commands in folded scalars so the literal docker://… strings no longer confuse the YAML parser 2025-11-07 01:07:53 +01:00
2178 changed files with 172085 additions and 84 deletions

2
.dockerignore Normal file
View File

@@ -0,0 +1,2 @@
ci/dev/mongo.key*

26
.gitignore vendored Normal file
View File

@@ -0,0 +1,26 @@
.env.version
*.pb.go
*.pb.gw.go
pubspec.lock
.DS_Store
analysis_options.yaml
devtools_options.yaml
untranslated.txt
generate_protos.sh
update_dep.sh
test.sh
.vscode/
.gocache/
.cache/
.claude/
# Air hot reload build artifacts
**/tmp/
build-errors.log
# Development environment (NEVER commit credentials!)
.env.dev
vault-keys.txt
.vault_token
CLAUDE.md

74
.woodpecker/bff.yml Normal file
View File

@@ -0,0 +1,74 @@
matrix:
include:
- BFF_IMAGE_PATH: bff/service
BFF_DOCKERFILE: ci/prod/compose/bff.dockerfile
BFF_MONGO_SECRET_PATH: sendico/db
BFF_API_SECRET_PATH: sendico/api/endpoint
BFF_ENV: prod
when:
- event: push
branch: main
steps:
- name: version
image: alpine:latest
commands:
- set -euo pipefail 2>/dev/null || set -eu
- apk add --no-cache git
- GIT_REV="$(git rev-parse --short HEAD)"
- BUILD_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
- APP_V="$(cat version)"
- BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
- BUILD_USER="${WOODPECKER_MACHINE:-woodpecker}"
- printf "GIT_REV=%s\nBUILD_BRANCH=%s\nAPP_V=%s\nBUILD_DATE=%s\nBUILD_USER=%s\n" \
"$GIT_REV" "$BUILD_BRANCH" "$APP_V" "$BUILD_DATE" "$BUILD_USER" | tee .env.version
- name: proto
image: golang:alpine
depends_on: [ version ]
commands:
- set -eu
- 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
- export PATH="$(go env GOPATH)/bin:$PATH"
- bash ci/scripts/proto/generate.sh
- name: secrets
image: alpine:latest
depends_on: [ version ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash coreutils openssh-keygen curl sed python3
- mkdir -p secrets
- ./ci/vlt kv_to_file kv ops/deploy/ssh_key private_b64 secrets/SSH_KEY.b64 600
- base64 -d secrets/SSH_KEY.b64 > secrets/SSH_KEY
- chmod 600 secrets/SSH_KEY
- ssh-keygen -y -f secrets/SSH_KEY >/dev/null
- ./ci/vlt kv_get kv registry user > secrets/REGISTRY_USER
- ./ci/vlt kv_get kv registry password > secrets/REGISTRY_PASSWORD
- name: build-image
image: gcr.io/kaniko-project/executor:debug
depends_on: [ proto, secrets ]
commands:
- sh ci/scripts/bff/build-image.sh
- name: deploy
image: alpine:latest
depends_on: [ secrets, build-image ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash openssh-client rsync coreutils curl sed python3
- mkdir -p /root/.ssh
- install -m 600 secrets/SSH_KEY /root/.ssh/id_rsa
- sh ci/scripts/bff/deploy.sh

View File

@@ -0,0 +1,73 @@
matrix:
include:
- DOCUMENTS_IMAGE_PATH: billing/documents
DOCUMENTS_DOCKERFILE: ci/prod/compose/billing_documents.dockerfile
DOCUMENTS_MONGO_SECRET_PATH: sendico/db
DOCUMENTS_ENV: prod
when:
- event: push
branch: main
steps:
- name: version
image: alpine:latest
commands:
- set -euo pipefail 2>/dev/null || set -eu
- apk add --no-cache git
- GIT_REV="$(git rev-parse --short HEAD)"
- BUILD_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
- APP_V="$(cat version)"
- BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
- BUILD_USER="${WOODPECKER_MACHINE:-woodpecker}"
- printf "GIT_REV=%s\nBUILD_BRANCH=%s\nAPP_V=%s\nBUILD_DATE=%s\nBUILD_USER=%s\n" \
"$GIT_REV" "$BUILD_BRANCH" "$APP_V" "$BUILD_DATE" "$BUILD_USER" | tee .env.version
- name: proto
image: golang:alpine
depends_on: [ version ]
commands:
- set -eu
- 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
- export PATH="$(go env GOPATH)/bin:$PATH"
- bash ci/scripts/proto/generate.sh
- name: secrets
image: alpine:latest
depends_on: [ version ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash coreutils openssh-keygen curl sed python3
- mkdir -p secrets
- ./ci/vlt kv_to_file kv ops/deploy/ssh_key private_b64 secrets/SSH_KEY.b64 600
- base64 -d secrets/SSH_KEY.b64 > secrets/SSH_KEY
- chmod 600 secrets/SSH_KEY
- ssh-keygen -y -f secrets/SSH_KEY >/dev/null
- ./ci/vlt kv_get kv registry user > secrets/REGISTRY_USER
- ./ci/vlt kv_get kv registry password > secrets/REGISTRY_PASSWORD
- name: build-image
image: gcr.io/kaniko-project/executor:debug
depends_on: [ proto, secrets ]
commands:
- sh ci/scripts/billing_documents/build-image.sh
- name: deploy
image: alpine:latest
depends_on: [ secrets, build-image ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash openssh-client rsync coreutils curl sed python3
- mkdir -p /root/.ssh
- install -m 600 secrets/SSH_KEY /root/.ssh/id_rsa
- sh ci/scripts/billing_documents/deploy.sh

View File

@@ -0,0 +1,73 @@
matrix:
include:
- FEES_IMAGE_PATH: billing/fees
FEES_DOCKERFILE: ci/prod/compose/billing_fees.dockerfile
FEES_MONGO_SECRET_PATH: sendico/db
FEES_ENV: prod
when:
- event: push
branch: main
steps:
- name: version
image: alpine:latest
commands:
- set -euo pipefail 2>/dev/null || set -eu
- apk add --no-cache git
- GIT_REV="$(git rev-parse --short HEAD)"
- BUILD_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
- APP_V="$(cat version)"
- BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
- BUILD_USER="${WOODPECKER_MACHINE:-woodpecker}"
- printf "GIT_REV=%s\nBUILD_BRANCH=%s\nAPP_V=%s\nBUILD_DATE=%s\nBUILD_USER=%s\n" \
"$GIT_REV" "$BUILD_BRANCH" "$APP_V" "$BUILD_DATE" "$BUILD_USER" | tee .env.version
- name: proto
image: golang:alpine
depends_on: [ version ]
commands:
- set -eu
- 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
- export PATH="$(go env GOPATH)/bin:$PATH"
- bash ci/scripts/proto/generate.sh
- name: secrets
image: alpine:latest
depends_on: [ version ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash coreutils openssh-keygen curl sed python3
- mkdir -p secrets
- ./ci/vlt kv_to_file kv ops/deploy/ssh_key private_b64 secrets/SSH_KEY.b64 600
- base64 -d secrets/SSH_KEY.b64 > secrets/SSH_KEY
- chmod 600 secrets/SSH_KEY
- ssh-keygen -y -f secrets/SSH_KEY >/dev/null
- ./ci/vlt kv_get kv registry user > secrets/REGISTRY_USER
- ./ci/vlt kv_get kv registry password > secrets/REGISTRY_PASSWORD
- name: build-image
image: gcr.io/kaniko-project/executor:debug
depends_on: [ proto, secrets ]
commands:
- sh ci/scripts/billing_fees/build-image.sh
- name: deploy
image: alpine:latest
depends_on: [ secrets, build-image ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash openssh-client rsync coreutils curl sed python3
- mkdir -p /root/.ssh
- install -m 600 secrets/SSH_KEY /root/.ssh/id_rsa
- sh ci/scripts/billing_fees/deploy.sh

View File

@@ -6,6 +6,7 @@ steps:
- name: version
image: alpine:latest
commands:
- set -euo pipefail
- apk add --no-cache git
- GIT_REV="$(git rev-parse --short HEAD)"
- BUILD_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
@@ -16,63 +17,36 @@ steps:
image: alpine:latest
depends_on: [ version ]
environment:
VAULT_ADDR: https://vault.sendico.io
VAULT_ROLE_ID: { from_secret: VAULT_ROLE_ID }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
# CI's own AppRole creds for accessing Vault to fetch the SSH key (existing names)
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- apk add --no-cache curl bash coreutils sed
- set -euo pipefail
- apk add --no-cache bash coreutils openssh-keygen curl sed python3
- mkdir -p secrets
- set -a; . ./.env.version; set +a
# fetch registry creds
- ./ci/vlt kv_to_file kv sendico/registry user secrets/REGISTRY_USER 600
- ./ci/vlt kv_to_file kv sendico/registry password secrets/REGISTRY_PASS 600
# fetch SSH private key for deploy
- ./ci/vlt kv_to_file kv sendico/ops/deploy/ssh_key private secrets/SSH_KEY 600
- name: lock-db
image: quay.io/skopeo/stable:latest
depends_on: [ secrets ]
environment:
REGISTRY_URL: registry.sendico.io
MONGO_VERSION: latest
commands:
- apk add --no-cache bash coreutils sed
- mkdir -p ci/prod/env
- set -a; . ./ci/prod/.env.runtime; set +a
- set -a; . ./.env.version; set +a
- test -s secrets/REGISTRY_USER && test -s secrets/REGISTRY_PASS
- CREDS="$(cat secrets/REGISTRY_USER):$(cat secrets/REGISTRY_PASS)"
# mirror multi-arch image into registry under app version tag
- skopeo copy --all docker://docker.io/library/mongo:${MONGO_VERSION} docker://${REGISTRY_URL}/mirror/mongo:${APP_V} --dest-creds "$CREDS"
# inspect the mirrored image to capture immutable digest
- INSPECT=$(skopeo inspect docker://${REGISTRY_URL}/mirror/mongo:${APP_V} --creds "$CREDS")
- DIGEST="$(printf '%s' "$INSPECT" | tr -d '\n' | sed -n 's/.*"Digest"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')"
- test -n "$DIGEST"
# store lock both for local deploy metadata and rsync to server
- printf 'MONGO_TAG=%s\nMONGO_DIGEST=%s\n' "$APP_V" "$DIGEST" | tee .env.lock ci/prod/env/.env.lock.db
- cat .env.lock
# Retrieve SSH private key for deploy (existing helper)
- ./ci/vlt kv_to_file kv ops/deploy/ssh_key private_b64 secrets/SSH_KEY.b64 600
- base64 -d secrets/SSH_KEY.b64 > secrets/SSH_KEY
- chmod 600 secrets/SSH_KEY
- ssh-keygen -y -f secrets/SSH_KEY >/dev/null
- name: deploy
image: alpine:latest
depends_on: [ lock-db ]
depends_on: [ secrets ]
# Reuse the SAME Woodpecker secrets to pass AppRole to the Vault Agent at runtime
environment:
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- apk add --no-cache openssh-client rsync
- set -a; . ./ci/prod/.env.runtime; set +a # SSH_HOST, SSH_USER, REMOTE_DIR берём из репо
- set -a; . ./.env.version; set +a
- set -euo pipefail
- apk add --no-cache bash openssh-client rsync coreutils
- mkdir -p /root/.ssh
- install -m 600 secrets/SSH_KEY /root/.ssh/id_rsa
# ensure target dir layout
- ssh -o StrictHostKeyChecking=no ${SSH_USER}@${SSH_HOST} "mkdir -p ${REMOTE_DIR}/{ops,vault/templates,backup,.woodpecker}"
# sync non-secret runtime files from repo → server
- rsync -avz --delete ci/prod/compose/ ${SSH_USER}@${SSH_HOST}:${REMOTE_BASE}/${DB_DIR}/compose/
- rsync -avz .woodpecker/ ${SSH_USER}@${SSH_HOST}:${REMOTE_DIR}/.woodpecker/
- rsync -avz ci/prod/.env.runtime ${SSH_USER}@${SSH_HOST}:${REMOTE_BASE}/${DB_DIR}/env/.env.runtime
- rsync -avz ci/prod/env/.env.lock.db ${SSH_USER}@${SSH_HOST}:${REMOTE_BASE}/${DB_DIR}/env/.env.lock.db
# upload the generated lock
- scp -o StrictHostKeyChecking=no .env.lock ${SSH_USER}@${SSH_HOST}:${REMOTE_DIR}/.env.lock
# deploy
- ssh -o StrictHostKeyChecking=no ${SSH_USER}@${SSH_HOST} "
set -euo pipefail
cd ${REMOTE_DIR}
docker compose -f .woodpecker/db.yml pull
docker compose -f .woodpecker/db.yml up -d --remove-orphans
"
- sed -i 's/\r$//' ./ci/prod/.env.runtime
- set -a
- . ./ci/prod/.env.runtime
- . ./.env.version
- set +a
- bash ci/prod/scripts/bootstrap/network.sh
- bash ci/prod/scripts/deploy/db.sh

72
.woodpecker/discovery.yml Normal file
View File

@@ -0,0 +1,72 @@
matrix:
include:
- DISCOVERY_IMAGE_PATH: discovery/service
DISCOVERY_DOCKERFILE: ci/prod/compose/discovery.dockerfile
DISCOVERY_ENV: prod
when:
- event: push
branch: main
steps:
- name: version
image: alpine:latest
commands:
- set -euo pipefail 2>/dev/null || set -eu
- apk add --no-cache git
- GIT_REV="$(git rev-parse --short HEAD)"
- BUILD_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
- APP_V="$(cat version)"
- BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
- BUILD_USER="${WOODPECKER_MACHINE:-woodpecker}"
- printf "GIT_REV=%s\nBUILD_BRANCH=%s\nAPP_V=%s\nBUILD_DATE=%s\nBUILD_USER=%s\n" \
"$GIT_REV" "$BUILD_BRANCH" "$APP_V" "$BUILD_DATE" "$BUILD_USER" | tee .env.version
- name: proto
image: golang:alpine
depends_on: [ version ]
commands:
- set -eu
- 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
- export PATH="$(go env GOPATH)/bin:$PATH"
- bash ci/scripts/proto/generate.sh
- name: secrets
image: alpine:latest
depends_on: [ version ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash coreutils openssh-keygen curl sed python3
- mkdir -p secrets
- ./ci/vlt kv_to_file kv ops/deploy/ssh_key private_b64 secrets/SSH_KEY.b64 600
- base64 -d secrets/SSH_KEY.b64 > secrets/SSH_KEY
- chmod 600 secrets/SSH_KEY
- ssh-keygen -y -f secrets/SSH_KEY >/dev/null
- ./ci/vlt kv_get kv registry user > secrets/REGISTRY_USER
- ./ci/vlt kv_get kv registry password > secrets/REGISTRY_PASSWORD
- name: build-image
image: gcr.io/kaniko-project/executor:debug
depends_on: [ proto, secrets ]
commands:
- sh ci/scripts/discovery/build-image.sh
- name: deploy
image: alpine:latest
depends_on: [ secrets, build-image ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash openssh-client rsync coreutils curl sed python3
- mkdir -p /root/.ssh
- install -m 600 secrets/SSH_KEY /root/.ssh/id_rsa
- sh ci/scripts/discovery/deploy.sh

61
.woodpecker/frontend.yml Normal file
View File

@@ -0,0 +1,61 @@
matrix:
include:
- FRONTEND_IMAGE_PATH: frontend/service
FRONTEND_DOCKERFILE: ci/prod/compose/frontend.dockerfile
FRONTEND_ENV: prod
when:
- event: push
branch: main
steps:
- name: version
image: alpine:latest
commands:
- set -euo pipefail 2>/dev/null || set -eu
- apk add --no-cache git
- GIT_REV="$(git rev-parse --short HEAD)"
- BUILD_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
- APP_V="$(cat version)"
- BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
- BUILD_USER="${WOODPECKER_MACHINE:-woodpecker}"
- printf "GIT_REV=%s\nBUILD_BRANCH=%s\nAPP_V=%s\nBUILD_DATE=%s\nBUILD_USER=%s\n" \
"$GIT_REV" "$BUILD_BRANCH" "$APP_V" "$BUILD_DATE" "$BUILD_USER" | tee .env.version
- name: secrets
image: alpine:latest
depends_on: [ version ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash coreutils openssh-keygen curl sed python3
- mkdir -p secrets
- ./ci/vlt kv_to_file kv ops/deploy/ssh_key private_b64 secrets/SSH_KEY.b64 600
- base64 -d secrets/SSH_KEY.b64 > secrets/SSH_KEY
- chmod 600 secrets/SSH_KEY
- ssh-keygen -y -f secrets/SSH_KEY >/dev/null
- ./ci/vlt kv_get kv registry user > secrets/REGISTRY_USER
- ./ci/vlt kv_get kv registry password > secrets/REGISTRY_PASSWORD
- name: build-image
image: gcr.io/kaniko-project/executor:debug
depends_on: [ version, secrets ]
commands:
- sh ci/scripts/frontend/build-image.sh
- name: deploy
image: alpine:latest
depends_on: [ secrets, build-image ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash openssh-client rsync coreutils curl sed python3
- mkdir -p /root/.ssh
- install -m 600 secrets/SSH_KEY /root/.ssh/id_rsa
- sh ci/scripts/frontend/deploy.sh

View File

@@ -0,0 +1,77 @@
matrix:
include:
- FX_PIPELINE: fx_ingestor
FX_IMAGE_PATH: fx/ingestor
FX_DOCKERFILE: ci/prod/compose/fx_ingestor.dockerfile
FX_DEPLOY_TARGET: ingestor
FX_MONGO_SECRET_PATH: sendico/db
FX_NEEDS_NATS: "true"
FX_ENV: prod
when:
- event: push
branch: main
steps:
- name: version
image: alpine:latest
commands:
- set -euo pipefail 2>/dev/null || set -eu
- apk add --no-cache git
- GIT_REV="$(git rev-parse --short HEAD)"
- BUILD_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
- APP_V="$(cat version)"
- BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
- BUILD_USER="${WOODPECKER_MACHINE:-woodpecker}"
- printf "GIT_REV=%s\nBUILD_BRANCH=%s\nAPP_V=%s\nBUILD_DATE=%s\nBUILD_USER=%s\n" \
"$GIT_REV" "$BUILD_BRANCH" "$APP_V" "$BUILD_DATE" "$BUILD_USER" | tee .env.version
- name: proto
image: golang:alpine
depends_on: [ version ]
commands:
- set -eu
# protoc + headers; protobuf runtime pkg is not needed for codegen
- 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
- export PATH="$(go env GOPATH)/bin:$PATH"
- bash ci/scripts/proto/generate.sh
- name: secrets
image: alpine:latest
depends_on: [ version ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash coreutils openssh-keygen curl sed python3
- mkdir -p secrets
- ./ci/vlt kv_to_file kv ops/deploy/ssh_key private_b64 secrets/SSH_KEY.b64 600
- base64 -d secrets/SSH_KEY.b64 > secrets/SSH_KEY
- chmod 600 secrets/SSH_KEY
- ssh-keygen -y -f secrets/SSH_KEY >/dev/null
- ./ci/vlt kv_get kv registry user > secrets/REGISTRY_USER
- ./ci/vlt kv_get kv registry password > secrets/REGISTRY_PASSWORD
- name: build-image
image: gcr.io/kaniko-project/executor:debug
depends_on: [ proto, secrets ]
commands:
- sh ci/scripts/fx/build-image.sh
- name: deploy
image: alpine:latest
depends_on: [ secrets, build-image ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash openssh-client rsync coreutils curl sed python3
- mkdir -p /root/.ssh
- install -m 600 secrets/SSH_KEY /root/.ssh/id_rsa
- sh ci/scripts/fx/deploy.sh

77
.woodpecker/fx_oracle.yml Normal file
View File

@@ -0,0 +1,77 @@
matrix:
include:
- FX_PIPELINE: fx_oracle
FX_IMAGE_PATH: fx/oracle
FX_DOCKERFILE: ci/prod/compose/fx_oracle.dockerfile
FX_DEPLOY_TARGET: oracle
FX_MONGO_SECRET_PATH: sendico/db
FX_NEEDS_NATS: "true"
FX_ENV: prod
when:
- event: push
branch: main
steps:
- name: version
image: alpine:latest
commands:
- set -euo pipefail 2>/dev/null || set -eu
- apk add --no-cache git
- GIT_REV="$(git rev-parse --short HEAD)"
- BUILD_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
- APP_V="$(cat version)"
- BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
- BUILD_USER="${WOODPECKER_MACHINE:-woodpecker}"
- printf "GIT_REV=%s\nBUILD_BRANCH=%s\nAPP_V=%s\nBUILD_DATE=%s\nBUILD_USER=%s\n" \
"$GIT_REV" "$BUILD_BRANCH" "$APP_V" "$BUILD_DATE" "$BUILD_USER" | tee .env.version
- name: proto
image: golang:alpine
depends_on: [ version ]
commands:
- set -eu
# protoc + headers; protobuf runtime pkg is not needed for codegen
- 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
- export PATH="$(go env GOPATH)/bin:$PATH"
- bash ci/scripts/proto/generate.sh
- name: secrets
image: alpine:latest
depends_on: [ version ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash coreutils openssh-keygen curl sed python3
- mkdir -p secrets
- ./ci/vlt kv_to_file kv ops/deploy/ssh_key private_b64 secrets/SSH_KEY.b64 600
- base64 -d secrets/SSH_KEY.b64 > secrets/SSH_KEY
- chmod 600 secrets/SSH_KEY
- ssh-keygen -y -f secrets/SSH_KEY >/dev/null
- ./ci/vlt kv_get kv registry user > secrets/REGISTRY_USER
- ./ci/vlt kv_get kv registry password > secrets/REGISTRY_PASSWORD
- name: build-image
image: gcr.io/kaniko-project/executor:debug
depends_on: [ proto, secrets ]
commands:
- sh ci/scripts/fx/build-image.sh
- name: deploy
image: alpine:latest
depends_on: [ secrets, build-image ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash openssh-client rsync coreutils curl sed python3
- mkdir -p /root/.ssh
- install -m 600 secrets/SSH_KEY /root/.ssh/id_rsa
- sh ci/scripts/fx/deploy.sh

View File

@@ -0,0 +1,76 @@
matrix:
include:
- CHAIN_GATEWAY_IMAGE_PATH: gateway/chain
CHAIN_GATEWAY_DOCKERFILE: ci/prod/compose/chain_gateway.dockerfile
CHAIN_GATEWAY_MONGO_SECRET_PATH: sendico/db
CHAIN_GATEWAY_RPC_SECRET_PATH: sendico/gateway/chain
CHAIN_GATEWAY_WALLET_SECRET_PATH: sendico/gateway/chain/wallet
CHAIN_GATEWAY_VAULT_SECRET_PATH: sendico/gateway/chain/vault
CHAIN_GATEWAY_ENV: prod
when:
- event: push
branch: main
steps:
- name: version
image: alpine:latest
commands:
- set -euo pipefail 2>/dev/null || set -eu
- apk add --no-cache git
- GIT_REV="$(git rev-parse --short HEAD)"
- BUILD_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
- APP_V="$(cat version)"
- BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
- BUILD_USER="${WOODPECKER_MACHINE:-woodpecker}"
- printf "GIT_REV=%s\nBUILD_BRANCH=%s\nAPP_V=%s\nBUILD_DATE=%s\nBUILD_USER=%s\n" \
"$GIT_REV" "$BUILD_BRANCH" "$APP_V" "$BUILD_DATE" "$BUILD_USER" | tee .env.version
- name: proto
image: golang:alpine
depends_on: [ version ]
commands:
- set -eu
- 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
- export PATH="$(go env GOPATH)/bin:$PATH"
- bash ci/scripts/proto/generate.sh
- name: secrets
image: alpine:latest
depends_on: [ version ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash coreutils openssh-keygen curl sed python3
- mkdir -p secrets
- ./ci/vlt kv_to_file kv ops/deploy/ssh_key private_b64 secrets/SSH_KEY.b64 600
- base64 -d secrets/SSH_KEY.b64 > secrets/SSH_KEY
- chmod 600 secrets/SSH_KEY
- ssh-keygen -y -f secrets/SSH_KEY >/dev/null
- ./ci/vlt kv_get kv registry user > secrets/REGISTRY_USER
- ./ci/vlt kv_get kv registry password > secrets/REGISTRY_PASSWORD
- name: build-image
image: gcr.io/kaniko-project/executor:debug
depends_on: [ proto, secrets ]
commands:
- sh ci/scripts/chain_gateway/build-image.sh
- name: deploy
image: alpine:latest
depends_on: [ secrets, build-image ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash openssh-client rsync coreutils curl sed python3
- mkdir -p /root/.ssh
- install -m 600 secrets/SSH_KEY /root/.ssh/id_rsa
- sh ci/scripts/chain_gateway/deploy.sh

View File

@@ -0,0 +1,75 @@
matrix:
include:
- MNTX_GATEWAY_IMAGE_PATH: gateway/mntx
MNTX_GATEWAY_DOCKERFILE: ci/prod/compose/mntx_gateway.dockerfile
MNTX_GATEWAY_ENV: prod
MNTX_GATEWAY_MONETIX_SECRET_PATH: sendico/gateway/monetix
MNTX_GATEWAY_NATS_SECRET_PATH: sendico/nats
MNTX_GATEWAY_MONGO_SECRET_PATH: sendico/db
when:
- event: push
branch: main
steps:
- name: version
image: alpine:latest
commands:
- set -euo pipefail 2>/dev/null || set -eu
- apk add --no-cache git
- GIT_REV="$(git rev-parse --short HEAD)"
- BUILD_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
- APP_V="$(cat version)"
- BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
- BUILD_USER="${WOODPECKER_MACHINE:-woodpecker}"
- printf "GIT_REV=%s\nBUILD_BRANCH=%s\nAPP_V=%s\nBUILD_DATE=%s\nBUILD_USER=%s\n" \
"$GIT_REV" "$BUILD_BRANCH" "$APP_V" "$BUILD_DATE" "$BUILD_USER" | tee .env.version
- name: proto
image: golang:alpine
depends_on: [ version ]
commands:
- set -eu
- 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
- export PATH="$(go env GOPATH)/bin:$PATH"
- bash ci/scripts/proto/generate.sh
- name: secrets
image: alpine:latest
depends_on: [ version ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash coreutils openssh-keygen curl sed python3
- mkdir -p secrets
- ./ci/vlt kv_to_file kv ops/deploy/ssh_key private_b64 secrets/SSH_KEY.b64 600
- base64 -d secrets/SSH_KEY.b64 > secrets/SSH_KEY
- chmod 600 secrets/SSH_KEY
- ssh-keygen -y -f secrets/SSH_KEY >/dev/null
- ./ci/vlt kv_get kv registry user > secrets/REGISTRY_USER
- ./ci/vlt kv_get kv registry password > secrets/REGISTRY_PASSWORD
- name: build-image
image: gcr.io/kaniko-project/executor:debug
depends_on: [ proto, secrets ]
commands:
- sh ci/scripts/mntx/build-image.sh
- name: deploy
image: alpine:latest
depends_on: [ secrets, build-image ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash openssh-client rsync coreutils curl sed python3
- mkdir -p /root/.ssh
- install -m 600 secrets/SSH_KEY /root/.ssh/id_rsa
- sh ci/scripts/mntx/deploy.sh

View File

@@ -0,0 +1,73 @@
matrix:
include:
- TGSETTLE_GATEWAY_IMAGE_PATH: gateway/tgsettle
TGSETTLE_GATEWAY_DOCKERFILE: ci/prod/compose/tgsettle_gateway.dockerfile
TGSETTLE_GATEWAY_MONGO_SECRET_PATH: sendico/db
TGSETTLE_GATEWAY_ENV: prod
when:
- event: push
branch: main
steps:
- name: version
image: alpine:latest
commands:
- set -euo pipefail 2>/dev/null || set -eu
- apk add --no-cache git
- GIT_REV="$(git rev-parse --short HEAD)"
- BUILD_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
- APP_V="$(cat version)"
- BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
- BUILD_USER="${WOODPECKER_MACHINE:-woodpecker}"
- printf "GIT_REV=%s\nBUILD_BRANCH=%s\nAPP_V=%s\nBUILD_DATE=%s\nBUILD_USER=%s\n" \
"$GIT_REV" "$BUILD_BRANCH" "$APP_V" "$BUILD_DATE" "$BUILD_USER" | tee .env.version
- name: proto
image: golang:alpine
depends_on: [ version ]
commands:
- set -eu
- 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
- export PATH="$(go env GOPATH)/bin:$PATH"
- bash ci/scripts/proto/generate.sh
- name: secrets
image: alpine:latest
depends_on: [ version ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash coreutils openssh-keygen curl sed python3
- mkdir -p secrets
- ./ci/vlt kv_to_file kv ops/deploy/ssh_key private_b64 secrets/SSH_KEY.b64 600
- base64 -d secrets/SSH_KEY.b64 > secrets/SSH_KEY
- chmod 600 secrets/SSH_KEY
- ssh-keygen -y -f secrets/SSH_KEY >/dev/null
- ./ci/vlt kv_get kv registry user > secrets/REGISTRY_USER
- ./ci/vlt kv_get kv registry password > secrets/REGISTRY_PASSWORD
- name: build-image
image: gcr.io/kaniko-project/executor:debug
depends_on: [ proto, secrets ]
commands:
- sh ci/scripts/tgsettle/build-image.sh
- name: deploy
image: alpine:latest
depends_on: [ secrets, build-image ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash openssh-client rsync coreutils curl sed python3
- mkdir -p /root/.ssh
- install -m 600 secrets/SSH_KEY /root/.ssh/id_rsa
- sh ci/scripts/tgsettle/deploy.sh

View File

@@ -0,0 +1,76 @@
matrix:
include:
- TRON_GATEWAY_IMAGE_PATH: gateway/tron
TRON_GATEWAY_DOCKERFILE: ci/prod/compose/tron_gateway.dockerfile
TRON_GATEWAY_MONGO_SECRET_PATH: sendico/db
TRON_GATEWAY_RPC_SECRET_PATH: sendico/gateway/tron
TRON_GATEWAY_WALLET_SECRET_PATH: sendico/gateway/tron/wallet
TRON_GATEWAY_VAULT_SECRET_PATH: sendico/gateway/tron/vault
TRON_GATEWAY_ENV: prod
when:
- event: push
branch: main
steps:
- name: version
image: alpine:latest
commands:
- set -euo pipefail 2>/dev/null || set -eu
- apk add --no-cache git
- GIT_REV="$(git rev-parse --short HEAD)"
- BUILD_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
- APP_V="$(cat version)"
- BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
- BUILD_USER="${WOODPECKER_MACHINE:-woodpecker}"
- printf "GIT_REV=%s\nBUILD_BRANCH=%s\nAPP_V=%s\nBUILD_DATE=%s\nBUILD_USER=%s\n" \
"$GIT_REV" "$BUILD_BRANCH" "$APP_V" "$BUILD_DATE" "$BUILD_USER" | tee .env.version
- name: proto
image: golang:alpine
depends_on: [ version ]
commands:
- set -eu
- 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
- export PATH="$(go env GOPATH)/bin:$PATH"
- bash ci/scripts/proto/generate.sh
- name: secrets
image: alpine:latest
depends_on: [ version ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash coreutils openssh-keygen curl sed python3
- mkdir -p secrets
- ./ci/vlt kv_to_file kv ops/deploy/ssh_key private_b64 secrets/SSH_KEY.b64 600
- base64 -d secrets/SSH_KEY.b64 > secrets/SSH_KEY
- chmod 600 secrets/SSH_KEY
- ssh-keygen -y -f secrets/SSH_KEY >/dev/null
- ./ci/vlt kv_get kv registry user > secrets/REGISTRY_USER
- ./ci/vlt kv_get kv registry password > secrets/REGISTRY_PASSWORD
- name: build-image
image: gcr.io/kaniko-project/executor:debug
depends_on: [ proto, secrets ]
commands:
- sh ci/scripts/tron_gateway/build-image.sh
- name: deploy
image: alpine:latest
depends_on: [ secrets, build-image ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash openssh-client rsync coreutils curl sed python3
- mkdir -p /root/.ssh
- install -m 600 secrets/SSH_KEY /root/.ssh/id_rsa
- sh ci/scripts/tron_gateway/deploy.sh

73
.woodpecker/ledger.yml Normal file
View File

@@ -0,0 +1,73 @@
matrix:
include:
- LEDGER_IMAGE_PATH: ledger/service
LEDGER_DOCKERFILE: ci/prod/compose/ledger.dockerfile
LEDGER_MONGO_SECRET_PATH: sendico/db
LEDGER_ENV: prod
when:
- event: push
branch: main
steps:
- name: version
image: alpine:latest
commands:
- set -euo pipefail 2>/dev/null || set -eu
- apk add --no-cache git
- GIT_REV="$(git rev-parse --short HEAD)"
- BUILD_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
- APP_V="$(cat version)"
- BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
- BUILD_USER="${WOODPECKER_MACHINE:-woodpecker}"
- printf "GIT_REV=%s\nBUILD_BRANCH=%s\nAPP_V=%s\nBUILD_DATE=%s\nBUILD_USER=%s\n" \
"$GIT_REV" "$BUILD_BRANCH" "$APP_V" "$BUILD_DATE" "$BUILD_USER" | tee .env.version
- name: proto
image: golang:alpine
depends_on: [ version ]
commands:
- set -eu
- 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
- export PATH="$(go env GOPATH)/bin:$PATH"
- bash ci/scripts/proto/generate.sh
- name: secrets
image: alpine:latest
depends_on: [ version ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash coreutils openssh-keygen curl sed python3
- mkdir -p secrets
- ./ci/vlt kv_to_file kv ops/deploy/ssh_key private_b64 secrets/SSH_KEY.b64 600
- base64 -d secrets/SSH_KEY.b64 > secrets/SSH_KEY
- chmod 600 secrets/SSH_KEY
- ssh-keygen -y -f secrets/SSH_KEY >/dev/null
- ./ci/vlt kv_get kv registry user > secrets/REGISTRY_USER
- ./ci/vlt kv_get kv registry password > secrets/REGISTRY_PASSWORD
- name: build-image
image: gcr.io/kaniko-project/executor:debug
depends_on: [ proto, secrets ]
commands:
- sh ci/scripts/ledger/build-image.sh
- name: deploy
image: alpine:latest
depends_on: [ secrets, build-image ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash openssh-client rsync coreutils curl sed python3
- mkdir -p /root/.ssh
- install -m 600 secrets/SSH_KEY /root/.ssh/id_rsa
- sh ci/scripts/ledger/deploy.sh

52
.woodpecker/nats.yml Normal file
View File

@@ -0,0 +1,52 @@
when:
- event: push
branch: main
steps:
- name: version
image: alpine:latest
commands:
- set -euo pipefail
- apk add --no-cache git
- GIT_REV="$(git rev-parse --short HEAD)"
- BUILD_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
- APP_V="$(cat version)"
- printf "GIT_REV=%s\nBUILD_BRANCH=%s\nAPP_V=%s\n" "$GIT_REV" "$BUILD_BRANCH" "$APP_V" | tee .env.version
- name: secrets
image: alpine:latest
depends_on: [ version ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash coreutils openssh-keygen curl sed python3
- mkdir -p secrets
- ./ci/vlt kv_to_file kv ops/deploy/ssh_key private_b64 secrets/SSH_KEY.b64 600
- base64 -d secrets/SSH_KEY.b64 > secrets/SSH_KEY
- chmod 600 secrets/SSH_KEY
- ssh-keygen -y -f secrets/SSH_KEY >/dev/null
- name: deploy
image: alpine:latest
depends_on: [ secrets ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash openssh-client rsync coreutils curl sed python3
- mkdir -p /root/.ssh
- install -m 600 secrets/SSH_KEY /root/.ssh/id_rsa
- sed -i 's/\r$//' ./ci/prod/.env.runtime
- set -a
- . ./ci/prod/.env.runtime
- . ./.env.version
- set +a
- export NATS_USER="$(./ci/vlt kv_get kv sendico/nats user)"
- export NATS_PASSWORD="$(./ci/vlt kv_get kv sendico/nats password)"
- bash ci/prod/scripts/bootstrap/network.sh
- bash ci/prod/scripts/deploy/nats.sh

View File

@@ -0,0 +1,76 @@
matrix:
include:
- NOTIFICATION_IMAGE_PATH: notification/service
NOTIFICATION_DOCKERFILE: ci/prod/compose/notification.dockerfile
NOTIFICATION_MONGO_SECRET_PATH: sendico/db
NOTIFICATION_MAIL_SECRET_PATH: sendico/notification/mail
NOTIFICATION_API_SECRET_PATH: sendico/api/endpoint
NOTIFICATION_TELEGRAM_SECRET_PATH: sendico/notification/telegram
NOTIFICATION_ENV: prod
when:
- event: push
branch: main
steps:
- name: version
image: alpine:latest
commands:
- set -euo pipefail 2>/dev/null || set -eu
- apk add --no-cache git
- GIT_REV="$(git rev-parse --short HEAD)"
- BUILD_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
- APP_V="$(cat version)"
- BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
- BUILD_USER="${WOODPECKER_MACHINE:-woodpecker}"
- printf "GIT_REV=%s\nBUILD_BRANCH=%s\nAPP_V=%s\nBUILD_DATE=%s\nBUILD_USER=%s\n" \
"$GIT_REV" "$BUILD_BRANCH" "$APP_V" "$BUILD_DATE" "$BUILD_USER" | tee .env.version
- name: proto
image: golang:alpine
depends_on: [ version ]
commands:
- set -eu
- 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
- export PATH="$(go env GOPATH)/bin:$PATH"
- bash ci/scripts/proto/generate.sh
- name: secrets
image: alpine:latest
depends_on: [ version ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash coreutils openssh-keygen curl sed python3
- mkdir -p secrets
- ./ci/vlt kv_to_file kv ops/deploy/ssh_key private_b64 secrets/SSH_KEY.b64 600
- base64 -d secrets/SSH_KEY.b64 > secrets/SSH_KEY
- chmod 600 secrets/SSH_KEY
- ssh-keygen -y -f secrets/SSH_KEY >/dev/null
- ./ci/vlt kv_get kv registry user > secrets/REGISTRY_USER
- ./ci/vlt kv_get kv registry password > secrets/REGISTRY_PASSWORD
- name: build-image
image: gcr.io/kaniko-project/executor:debug
depends_on: [ proto, secrets ]
commands:
- sh ci/scripts/notification/build-image.sh
- name: deploy
image: alpine:latest
depends_on: [ secrets, build-image ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash openssh-client rsync coreutils curl sed python3
- mkdir -p /root/.ssh
- install -m 600 secrets/SSH_KEY /root/.ssh/id_rsa
- sh ci/scripts/notification/deploy.sh

View File

@@ -0,0 +1,73 @@
matrix:
include:
- PAYMENTS_IMAGE_PATH: payments/orchestrator
PAYMENTS_DOCKERFILE: ci/prod/compose/payments_orchestrator.dockerfile
PAYMENTS_MONGO_SECRET_PATH: sendico/db
PAYMENTS_ENV: prod
when:
- event: push
branch: main
steps:
- name: version
image: alpine:latest
commands:
- set -euo pipefail 2>/dev/null || set -eu
- apk add --no-cache git
- GIT_REV="$(git rev-parse --short HEAD)"
- BUILD_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
- APP_V="$(cat version)"
- BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
- BUILD_USER="${WOODPECKER_MACHINE:-woodpecker}"
- printf "GIT_REV=%s\nBUILD_BRANCH=%s\nAPP_V=%s\nBUILD_DATE=%s\nBUILD_USER=%s\n" \
"$GIT_REV" "$BUILD_BRANCH" "$APP_V" "$BUILD_DATE" "$BUILD_USER" | tee .env.version
- name: proto
image: golang:alpine
depends_on: [ version ]
commands:
- set -eu
- 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
- export PATH="$(go env GOPATH)/bin:$PATH"
- bash ci/scripts/proto/generate.sh
- name: secrets
image: alpine:latest
depends_on: [ version ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash coreutils openssh-keygen curl sed python3
- mkdir -p secrets
- ./ci/vlt kv_to_file kv ops/deploy/ssh_key private_b64 secrets/SSH_KEY.b64 600
- base64 -d secrets/SSH_KEY.b64 > secrets/SSH_KEY
- chmod 600 secrets/SSH_KEY
- ssh-keygen -y -f secrets/SSH_KEY >/dev/null
- ./ci/vlt kv_get kv registry user > secrets/REGISTRY_USER
- ./ci/vlt kv_get kv registry password > secrets/REGISTRY_PASSWORD
- name: build-image
image: gcr.io/kaniko-project/executor:debug
depends_on: [ proto, secrets ]
commands:
- sh ci/scripts/payments_orchestrator/build-image.sh
- name: deploy
image: alpine:latest
depends_on: [ secrets, build-image ]
environment:
VAULT_ADDR: { from_secret: VAULT_ADDR }
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
commands:
- set -euo pipefail
- apk add --no-cache bash openssh-client rsync coreutils curl sed python3
- mkdir -p /root/.ssh
- install -m 600 secrets/SSH_KEY /root/.ssh/id_rsa
- sh ci/scripts/payments_orchestrator/deploy.sh

266
Makefile Normal file
View File

@@ -0,0 +1,266 @@
# Sendico Development Environment - Makefile
# Docker Compose + Makefile build system
.PHONY: help init build up down restart logs rebuild clean vault-init proto
COMPOSE := docker compose -f docker-compose.dev.yml --env-file .env.dev
SERVICE ?=
# Colors
GREEN := \033[0;32m
YELLOW := \033[1;33m
NC := \033[0m
help:
@echo "$(GREEN)Sendico Development Environment$(NC)"
@echo ""
@echo "$(YELLOW)Quick Start:$(NC)"
@echo " make init Initialize dev environment (first time setup)"
@echo " make up Start all services"
@echo " make vault-init Initialize Vault (if services need it)"
@echo ""
@echo "$(YELLOW)Main Commands:$(NC)"
@echo " make build Build all service images"
@echo " make down Stop all services"
@echo " make restart Restart all services"
@echo " make status Show service status"
@echo " make logs [SERVICE=x] View logs (all or specific service)"
@echo " make rebuild SERVICE=x Rebuild specific service"
@echo " make clean Remove all containers and volumes"
@echo ""
@echo "$(YELLOW)Selective Operations:$(NC)"
@echo " make infra-up Start infrastructure only (mongo, nats, vault)"
@echo " make services-up Start application services only"
@echo " make list-services List all available services"
@echo ""
@echo "$(YELLOW)Build Groups:$(NC)"
@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, mntx, tgsettle)"
@echo " make build-api Build API services (notification, bff)"
@echo " make build-frontend Build Flutter web frontend"
@echo ""
@echo "$(YELLOW)Development:$(NC)"
@echo " make proto Generate protobuf code"
@echo " make health Check service health"
@echo ""
@echo "Examples:"
@echo " make logs SERVICE=dev-ledger"
@echo " make rebuild SERVICE=dev-ledger"
# First-time initialization
init:
@echo "$(GREEN)Initializing development environment...$(NC)"
@if [ ! -f ci/dev/mongo-key/mongo.key ]; then \
echo "$(YELLOW)Generating MongoDB keyfile...$(NC)"; \
openssl rand -base64 756 | tr -d '\n' > ci/dev/mongo-key/mongo.key; \
chmod 400 ci/dev/mongo-key/mongo.key; \
fi
@if [ ! -f .env.dev ]; then \
echo "$(YELLOW)Creating .env.dev with default values...$(NC)"; \
echo "# Sendico Development Environment Configuration" > .env.dev; \
echo "# Simple plaintext credentials for infrastructure" >> .env.dev; \
echo "" >> .env.dev; \
echo "# MongoDB Configuration" >> .env.dev; \
echo "MONGO_USER=dev_root" >> .env.dev; \
echo "MONGO_PASSWORD=dev_password_123" >> .env.dev; \
echo "" >> .env.dev; \
echo "# NATS Configuration" >> .env.dev; \
echo "NATS_USER=dev_nats" >> .env.dev; \
echo "NATS_PASSWORD=nats_password_123" >> .env.dev; \
echo "" >> .env.dev; \
echo "# Vault Configuration (for application data only)" >> .env.dev; \
echo "VAULT_ADDR=http://dev-vault:8200" >> .env.dev; \
fi
@echo "$(GREEN)Verifying .env.dev...$(NC)"
@cat .env.dev | grep -q "MONGO_USER=" || (echo "$(YELLOW)Error: .env.dev is incomplete$(NC)" && exit 1)
@echo "$(GREEN)Running proto generation...$(NC)"
@./generate_protos.sh
@echo "$(GREEN)Building Docker images...$(NC)"
@$(COMPOSE) build
@echo "$(GREEN)✅ Initialization complete!$(NC)"
@echo ""
@echo "Next steps:"
@echo " 1. make up # Start services"
@echo " 2. make vault-init # Initialize Vault (if needed)"
# Build all images
build:
@echo "$(GREEN)Building all service images...$(NC)"
@./generate_protos.sh
@$(COMPOSE) build
# Start all services
up:
@echo "$(GREEN)Starting development environment...$(NC)"
@$(COMPOSE) up -d
@echo ""
@echo "$(GREEN)✅ Development environment started!$(NC)"
@echo ""
@echo "Services:"
@echo " MongoDB: mongodb://dev_root:dev_password_123@localhost:27017/admin?replicaSet=dev-rs"
@echo " NATS: nats://dev_nats:nats_password_123@localhost:4222"
@echo " NATS UI: http://localhost:8222"
@echo " Vault: http://localhost:8200 (run 'make vault-init' first)"
@echo ""
@echo "View logs: make logs [SERVICE=name]"
@echo "Stop: make down"
# Stop all services
down:
@echo "$(YELLOW)Stopping development environment...$(NC)"
@$(COMPOSE) down
# Restart all services
restart:
@echo "$(YELLOW)Restarting services...$(NC)"
@$(COMPOSE) restart
# View logs
logs:
ifdef SERVICE
@$(COMPOSE) logs -f $(SERVICE)
else
@$(COMPOSE) logs -f
endif
# Rebuild specific service
rebuild:
ifndef SERVICE
$(error SERVICE is required: make rebuild SERVICE=ledger)
endif
@echo "$(GREEN)Rebuilding $(SERVICE)...$(NC)"
@$(COMPOSE) build $(SERVICE)
@$(COMPOSE) up -d --force-recreate $(SERVICE)
@echo "$(GREEN)✅ $(SERVICE) rebuilt$(NC)"
@echo "View logs: make logs SERVICE=$(SERVICE)"
# Generate protobuf code
proto:
@echo "$(GREEN)Generating protobuf code...$(NC)"
@./generate_protos.sh
@echo "$(GREEN)✅ Protobuf generation complete$(NC)"
# Clean everything
clean:
@echo "$(YELLOW)WARNING: This will remove all containers and volumes!$(NC)"
@read -p "Are you sure? [y/N] " -n 1 -r; \
echo; \
if [[ $$REPLY =~ ^[Yy]$$ ]]; then \
$(COMPOSE) down -v --remove-orphans; \
docker system prune -f; \
echo "$(GREEN)✅ Cleanup complete$(NC)"; \
fi
# Initialize Vault (first time only)
vault-init:
@echo "$(GREEN)Initializing Vault...$(NC)"
@echo "$(YELLOW)Make sure Vault is running: make up$(NC)"
@sleep 2
@echo "Checking Vault status..."
@docker exec dev-vault vault status || echo "Vault not initialized yet"
@echo ""
@echo "$(GREEN)Initializing Vault with 1 key share...$(NC)"
@docker exec dev-vault vault operator init -key-shares=1 -key-threshold=1 > vault-keys.txt || echo "Vault already initialized"
@if [ -f vault-keys.txt ]; then \
echo "$(GREEN)✅ Vault initialized!$(NC)"; \
echo ""; \
echo "$(YELLOW)IMPORTANT: Save vault-keys.txt securely!$(NC)"; \
echo "It contains the unseal key and root token."; \
echo ""; \
UNSEAL_KEY=$$(grep 'Unseal Key 1:' vault-keys.txt | awk '{print $$NF}'); \
echo "Unsealing Vault..."; \
docker exec dev-vault vault operator unseal $$UNSEAL_KEY; \
echo ""; \
echo "$(GREEN)✅ Vault is unsealed and ready!$(NC)"; \
echo ""; \
echo "Root token: $$(grep 'Initial Root Token:' vault-keys.txt | awk '{print $$NF}')"; \
echo "UI: http://localhost:8200"; \
fi
# Infrastructure only (mongo + nats + vault)
infra-up:
@echo "$(GREEN)Starting infrastructure only...$(NC)"
@$(COMPOSE) up -d dev-mongo-1 dev-mongo-2 dev-mongo-3 dev-nats dev-vault
@$(COMPOSE) up dev-mongo-init
# Services only (assumes infra is running)
services-up:
@echo "$(GREEN)Starting application services...$(NC)"
@$(COMPOSE) up -d \
dev-discovery \
dev-fx-oracle \
dev-fx-ingestor \
dev-billing-fees \
dev-billing-documents \
dev-ledger \
dev-payments-orchestrator \
dev-chain-gateway \
dev-tron-gateway \
dev-mntx-gateway \
dev-tgsettle-gateway \
dev-notification \
dev-bff \
dev-frontend
# Status check
status:
@$(COMPOSE) ps
# List all services
list-services:
@echo "$(GREEN)Infrastructure Services:$(NC)"
@echo " - dev-mongo-1, dev-mongo-2, dev-mongo-3 (MongoDB Replica Set)"
@echo " - dev-nats (NATS with JetStream)"
@echo " - dev-vault (Vault for application secrets)"
@echo ""
@echo "$(GREEN)Application Services:$(NC)"
@echo " - dev-discovery :9407 (Service Registry)"
@echo " - dev-fx-oracle :50051, :9400 (FX Quotes)"
@echo " - dev-fx-ingestor :9102 (FX Rate Ingestion)"
@echo " - dev-billing-fees :50060, :9402 (Fee Calculation)"
@echo " - dev-billing-documents :50061, :9409 (Billing Documents)"
@echo " - dev-ledger :50052, :9401 (Double-Entry Ledger)"
@echo " - dev-payments-orchestrator :50062, :9403 (Payment Orchestration)"
@echo " - dev-chain-gateway :50070, :9404 (EVM Blockchain Gateway)"
@echo " - dev-tron-gateway :50071, :9408 (TRON Blockchain Gateway)"
@echo " - dev-mntx-gateway :50075, :9405, :8084 (Card Payouts)"
@echo " - dev-tgsettle-gateway :50080, :9406 (Telegram Settlements)"
@echo " - dev-notification :8081 (Notifications)"
@echo " - dev-bff :8080 (Backend for Frontend)"
@echo " - dev-frontend :3000 (Flutter Web UI)"
# Health check all services
health:
@echo "$(GREEN)Checking service health...$(NC)"
@$(COMPOSE) ps --format json | grep -v "State" || echo "Run 'make up' first"
# Build specific service group
build-infra:
@echo "$(GREEN)Building infrastructure images...$(NC)"
# Infrastructure uses official images, nothing to build
build-core:
@echo "$(GREEN)Building core services...$(NC)"
@$(COMPOSE) build dev-discovery dev-ledger dev-billing-fees dev-billing-documents
build-fx:
@echo "$(GREEN)Building FX services...$(NC)"
@$(COMPOSE) build dev-fx-oracle dev-fx-ingestor
build-payments:
@echo "$(GREEN)Building payment services...$(NC)"
@$(COMPOSE) build dev-payments-orchestrator
build-gateways:
@echo "$(GREEN)Building gateway services...$(NC)"
@$(COMPOSE) build dev-chain-gateway dev-tron-gateway dev-mntx-gateway dev-tgsettle-gateway
build-api:
@echo "$(GREEN)Building API services...$(NC)"
@$(COMPOSE) build dev-notification dev-bff
build-frontend:
@echo "$(GREEN)Building frontend...$(NC)"
@$(COMPOSE) build dev-frontend

399
SETUP.md Normal file
View File

@@ -0,0 +1,399 @@
# Sendico Development Environment - Setup Guide
Complete Docker Compose + Makefile build system for local development.
## 🎯 What's Included
**13 Services:**
- ✅ Discovery (Service Registry)
- ✅ FX Oracle & FX Ingestor
- ✅ Billing Fees
- ✅ Ledger (Double-Entry Accounting)
- ✅ Payments Orchestrator
- ✅ Chain Gateway (Blockchain)
- ✅ MNTX Gateway (Card Payouts)
- ✅ TGSettle Gateway (Telegram Settlements)
- ✅ Notification
- ✅ BFF (Backend for Frontend / Server)
- ✅ Frontend (Flutter Web)
**Infrastructure:**
- MongoDB Replica Set (3 nodes)
- NATS with JetStream
- Vault (single node, for application data only)
---
## 🚀 Quick Start
```bash
# 1. First time setup
make init
# 2. Start everything
make up
# 3. Initialize Vault (if services need blockchain keys, external API keys)
make vault-init
# 4. Check status
make status
# 5. View frontend
open http://localhost:3000
```
---
## 📋 Prerequisites
- Docker & Docker Compose
- Make
- Go 1.24+ (for local proto generation)
- protoc, protoc-gen-go, protoc-gen-go-grpc (for proto generation)
---
## 🔧 Configuration
### Environment Variables
Edit `.env.dev` (created after `make init`):
```bash
# MongoDB
MONGO_USER=dev_root
MONGO_PASSWORD=dev_password_123
# NATS
NATS_USER=dev_nats
NATS_PASSWORD=nats_password_123
# Vault (for application data only)
VAULT_ADDR=http://dev-vault:8200
```
**IMPORTANT:** These are plaintext credentials for dev infrastructure only!
---
## 📊 Service Ports
**Infrastructure:**
- MongoDB: `localhost:27017`
- NATS: `localhost:4222`
- NATS Monitoring: `localhost:8222`
- Vault: `localhost:8200`
**Services:**
- Discovery: `localhost:9407`
- FX Oracle: `localhost:50051` (gRPC), `localhost:9400` (metrics)
- FX Ingestor: `localhost:9102`
- Billing Fees: `localhost:50060` (gRPC), `localhost:9402` (metrics)
- Ledger: `localhost:50052` (gRPC), `localhost:9401` (metrics)
- Payments Orchestrator: `localhost:50062` (gRPC), `localhost:9403` (metrics)
- Chain Gateway: `localhost:50070` (gRPC), `localhost:9404` (metrics)
- MNTX Gateway: `localhost:50075` (gRPC), `localhost:9405` (metrics), `localhost:8084` (HTTP)
- TGSettle Gateway: `localhost:50080` (gRPC), `localhost:9406` (metrics)
- Notification: `localhost:8081`
- BFF: `localhost:8080`
- Frontend: `localhost:3000`
---
## 🛠️ Common Commands
### Lifecycle
```bash
make up # Start all services
make down # Stop all services
make restart # Restart all services
make status # Check status
make clean # Remove everything (containers + volumes)
```
### Development
```bash
# View logs
make logs # All services
make logs SERVICE=dev-ledger # Specific service
# Rebuild after code changes
make rebuild SERVICE=dev-ledger
# Regenerate protobuf
make proto
```
### Selective Startup
```bash
# Start infrastructure only
make infra-up
# Then start services
make services-up
# Or start specific service groups
make build-core # discovery, ledger, billing-fees
make build-fx # fx-oracle, fx-ingestor
make build-payments # payments-orchestrator
make build-gateways # chain, mntx, tgsettle
```
---
## 🔐 Vault Setup
Vault is **only for application data** (blockchain keys, external API keys).
Infrastructure credentials (MongoDB, NATS) are in `.env.dev`.
### Initialize Vault
```bash
make vault-init
```
This will:
1. Initialize Vault with 1 key share
2. Unseal Vault automatically
3. Save keys to `vault-keys.txt` (NEVER commit this!)
4. Display root token
### Using Vault in Services
Services that need Vault (e.g., Chain Gateway for blockchain keys):
1. Set `VAULT_ADDR` in service environment
2. Use Vault client to fetch secrets at runtime
3. Store secrets in Vault: `kv/data/chain/ethereum/private_key`
---
## 🏗️ Development Workflow
### Typical Day
```bash
# Morning: Start environment
make up
# Work on ledger service
vim api/ledger/internal/service/ledger/posting.go
# Rebuild ledger
make rebuild SERVICE=dev-ledger
# View logs
make logs SERVICE=dev-ledger
# Test
curl http://localhost:9401/health
# End of day
make down
```
### After Changing Protos
```bash
# Regenerate protos
make proto
# Rebuild affected services
make rebuild SERVICE=dev-ledger
make rebuild SERVICE=dev-payments-orchestrator
```
### Frontend Development
For faster iteration, run frontend locally instead of Docker:
```bash
# Start backend services only
make infra-up
make services-up
# Run frontend locally
cd frontend/pweb
flutter run -d chrome
```
---
## 🔍 Debugging
### MongoDB Replica Set Issues
```bash
# Check replica set status
docker exec -it dev-mongo-1 mongosh -u dev_root -p dev_password_123 --eval "rs.status()"
# Reinitialize
make down
make up
docker logs dev-mongo-init
```
### Service Can't Connect to MongoDB
```bash
# Check if replica set is initialized
docker logs dev-mongo-init
# Check MongoDB is healthy
docker ps | grep mongo
```
### Vault Sealed
```bash
# Get unseal key from vault-keys.txt
UNSEAL_KEY=$(grep 'Unseal Key 1:' vault-keys.txt | awk '{print $NF}')
# Unseal
docker exec dev-vault vault operator unseal $UNSEAL_KEY
```
### Service Crash Loop
```bash
# Check logs
make logs SERVICE=dev-ledger
# Check environment variables
docker inspect dev-ledger | grep -A 20 Env
# Rebuild from scratch
make rebuild SERVICE=dev-ledger
```
---
## 📦 Docker Images
All images tagged as `sendico-dev/<service>:latest`:
- `sendico-dev/discovery:latest`
- `sendico-dev/ledger:latest`
- `sendico-dev/billing-fees:latest`
- `sendico-dev/fx-oracle:latest`
- `sendico-dev/fx-ingestor:latest`
- `sendico-dev/payments-orchestrator:latest`
- `sendico-dev/chain-gateway:latest`
- `sendico-dev/mntx-gateway:latest`
- `sendico-dev/tgsettle-gateway:latest`
- `sendico-dev/notification:latest`
- `sendico-dev/bff:latest`
- `sendico-dev/frontend:latest`
---
## 🧪 Testing Full Flow
```bash
# 1. Start everything
make up
# 2. Check all services are healthy
make status
# 3. Test discovery
curl http://localhost:9407/health
# 4. Test ledger
curl http://localhost:9401/health
# 5. Test BFF
curl http://localhost:8080/api/v1/health
# 6. Test frontend
open http://localhost:3000
```
---
## 🗑️ Cleanup
```bash
# Stop everything
make down
# Remove volumes (fresh start)
make clean
# Remove images
docker rmi $(docker images 'sendico-dev/*' -q)
```
---
## 📂 File Structure
```
sendico/
├── docker-compose.dev.yml # All service definitions
├── .env.dev # Plaintext credentials
├── Makefile # Build commands
├── SETUP.md # This file
├── vault-keys.txt # Vault keys (gitignored)
└── docker/
└── dev/
├── README.md # Detailed docs
├── mongo.key # MongoDB keyfile
├── vault/
│ └── config.hcl # Vault config
└── *.dockerfile # Service builds
```
---
## 🆘 Getting Help
```bash
# Show all available commands
make help
# List all services
make list-services
# Check service health
make health
```
---
## 🎓 Next Steps
1. **Initialize Vault with secrets** for Chain Gateway
2. **Seed test data** into MongoDB
3. **Run integration tests**
4. **Add monitoring** (Prometheus/Grafana - optional)
5. **Document API endpoints** in each service
---
## ⚠️ Important Notes
- **Never commit `.env.dev`** - Contains credentials
- **Never commit `vault-keys.txt`** - Contains Vault keys
- **Vault is for app data only** - Not for infrastructure secrets
- **Use `dev-` prefix** for all service names to avoid conflicts
- **MongoDB keyfile** must have `400` permissions
---
## 📝 Troubleshooting Checklist
- [ ] Docker is running
- [ ] Docker Compose v2 is installed (`docker compose version`)
- [ ] `.env.dev` exists and has correct values
- [ ] Vault is initialized and unsealed (`make vault-init`)
- [ ] MongoDB replica set is initialized (`docker logs dev-mongo-init`)
- [ ] All services are healthy (`make status`)
- [ ] No port conflicts on host machine
- [ ] Proto generation succeeded (`make proto`)
---
**Ready to build? Run `make init && make up`** 🚀

View File

@@ -0,0 +1,46 @@
root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"
[build]
args_bin = []
entrypoint = "./tmp/main"
cmd = "go build -o ./tmp/main ."
delay = 1000
exclude_dir = ["assets", "tmp", "vendor", "testdata"]
exclude_file = []
exclude_regex = ["_test.go", "_templ.go"]
exclude_unchanged = false
follow_symlink = false
full_bin = ""
include_dir = []
include_ext = ["go", "tpl", "tmpl", "html"]
include_file = []
kill_delay = "0s"
log = "build-errors.log"
poll = false
poll_interval = 0
post_cmd = []
pre_cmd = []
rerun = false
rerun_delay = 500
send_interrupt = false
stop_on_error = false
[color]
app = ""
build = "yellow"
main = "magenta"
runner = "green"
watcher = "cyan"
[log]
main_only = false
time = false
[misc]
clean_on_exit = false
[screen]
clear_on_rebuild = false
keep_scroll = true

4
api/billing/documents/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
internal/generated
.gocache
/app
tmp

View File

@@ -0,0 +1,50 @@
runtime:
shutdown_timeout_seconds: 15
grpc:
network: tcp
address: ":50061"
advertise_host: "dev-billing-documents"
enable_reflection: true
enable_health: true
metrics:
address: ":9409"
database:
driver: mongodb
settings:
host_env: DOCUMENTS_MONGO_HOST
port_env: DOCUMENTS_MONGO_PORT
database_env: DOCUMENTS_MONGO_DATABASE
user_env: DOCUMENTS_MONGO_USER
password_env: DOCUMENTS_MONGO_PASSWORD
auth_source_env: DOCUMENTS_MONGO_AUTH_SOURCE
replica_set_env: DOCUMENTS_MONGO_REPLICA_SET
documents:
issuer:
legal_name: "Sendico Ltd"
legal_address: "12 Market Street, London, UK"
logo_path: "/assets/logo.png"
templates:
acceptance_path: "templates/acceptance.tpl"
protection:
owner_password: "sendico-documents"
storage:
driver: local_fs
local:
root_path: "tmp/documents"
messaging:
driver: NATS
settings:
url_env: NATS_URL
host_env: NATS_HOST
port_env: NATS_PORT
username_env: NATS_USER
password_env: NATS_PASSWORD
broker_name: Billing Documents Service
max_reconnects: 10
reconnect_wait: 5
buffer_size: 1024

View File

@@ -0,0 +1,56 @@
runtime:
shutdown_timeout_seconds: 15
grpc:
network: tcp
address: ":50061"
advertise_host: "sendico_billing_documents"
enable_reflection: true
enable_health: true
metrics:
address: ":9409"
database:
driver: mongodb
settings:
host_env: DOCUMENTS_MONGO_HOST
port_env: DOCUMENTS_MONGO_PORT
database_env: DOCUMENTS_MONGO_DATABASE
user_env: DOCUMENTS_MONGO_USER
password_env: DOCUMENTS_MONGO_PASSWORD
auth_source_env: DOCUMENTS_MONGO_AUTH_SOURCE
replica_set_env: DOCUMENTS_MONGO_REPLICA_SET
documents:
issuer:
legal_name: "Sendico Ltd"
legal_address: "12 Market Street, London, UK"
logo_path: "/assets/logo.png"
templates:
acceptance_path: "templates/acceptance.tpl"
protection:
owner_password: "sendico-documents"
storage:
driver: minio
s3:
endpoint: "s3.sendico.io"
region: "us-east-1"
bucket: "sendico-documents"
access_key_env: DOCUMENTS_S3_ACCESS_KEY
secret_access_key_env: DOCUMENTS_S3_SECRET_KEY
use_ssl: true
force_path_style: true
messaging:
driver: NATS
settings:
url_env: NATS_URL
host_env: NATS_HOST
port_env: NATS_PORT
username_env: NATS_USER
password_env: NATS_PASSWORD
broker_name: Billing Documents Service
max_reconnects: 10
reconnect_wait: 5
buffer_size: 1024

View File

@@ -0,0 +1,70 @@
module github.com/tech/sendico/billing/documents
go 1.25.6
replace github.com/tech/sendico/pkg => ../../pkg
require (
github.com/aws/aws-sdk-go-v2 v1.41.1
github.com/aws/aws-sdk-go-v2/config v1.32.7
github.com/aws/aws-sdk-go-v2/credentials v1.19.7
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0
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.78.0
gopkg.in/yaml.v3 v3.0.1
)
require (
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 // indirect
github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 // indirect
github.com/aws/smithy-go v1.24.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bmatcuk/doublestar/v4 v4.10.0 // indirect
github.com/casbin/casbin/v2 v2.135.0 // indirect
github.com/casbin/govaluate v1.10.0 // indirect
github.com/casbin/mongodb-adapter/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/go-chi/chi/v5 v5.2.4 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/klauspost/compress v1.18.3 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nats-io/nats.go v1.48.0 // indirect
github.com/nats-io/nkeys v0.4.15 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.67.5 // indirect
github.com/prometheus/procfs v0.19.2 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.2.0 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
golang.org/x/crypto v0.47.0 // indirect
golang.org/x/net v0.49.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.40.0 // indirect
golang.org/x/text v0.33.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260202165425-ce8ad4cf556b // indirect
google.golang.org/protobuf v1.36.11 // indirect
)

View File

@@ -0,0 +1,271 @@
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/aws/aws-sdk-go-v2 v1.41.1 h1:ABlyEARCDLN034NhxlRUSZr4l71mh+T5KAeGh6cerhU=
github.com/aws/aws-sdk-go-v2 v1.41.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4=
github.com/aws/aws-sdk-go-v2/config v1.32.7 h1:vxUyWGUwmkQ2g19n7JY/9YL8MfAIl7bTesIUykECXmY=
github.com/aws/aws-sdk-go-v2/config v1.32.7/go.mod h1:2/Qm5vKUU/r7Y+zUk/Ptt2MDAEKAfUtKc1+3U1Mo3oY=
github.com/aws/aws-sdk-go-v2/credentials v1.19.7 h1:tHK47VqqtJxOymRrNtUXN5SP/zUTvZKeLx4tH6PGQc8=
github.com/aws/aws-sdk-go-v2/credentials v1.19.7/go.mod h1:qOZk8sPDrxhf+4Wf4oT2urYJrYt3RejHSzgAquYeppw=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 h1:I0GyV8wiYrP8XpA70g1HBcQO1JlQxCMTW9npl5UbDHY=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17/go.mod h1:tyw7BOl5bBe/oqvoIeECFJjMdzXoa/dfVz3QQ5lgHGA=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 h1:xOLELNKGp2vsiteLsvLPwxC+mYmO6OZ8PYgiuPJzF8U=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17/go.mod h1:5M5CI3D12dNOtH3/mk6minaRwI2/37ifCURZISxA/IQ=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 h1:WWLqlh79iO48yLkj1v3ISRNiv+3KdQoZ6JWyfcsyQik=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17/go.mod h1:EhG22vHRrvF8oXSTYStZhJc1aUgKtnJe+aOiFEV90cM=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 h1:JqcdRG//czea7Ppjb+g/n4o8i/R50aTBHkA7vu0lK+k=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17/go.mod h1:CO+WeGmIdj/MlPel2KwID9Gt7CNq4M65HUfBW97liM0=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 h1:Z5EiPIzXKewUQK0QTMkutjiaPVeVYXX7KIqhXu/0fXs=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8/go.mod h1:FsTpJtvC4U1fyDXk7c71XoDv3HlRm8V3NiYLeYLh5YE=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 h1:RuNSMoozM8oXlgLG/n6WLaFGoea7/CddrCfIiSA+xdY=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17/go.mod h1:F2xxQ9TZz5gDWsclCtPQscGpP0VUOc8RqgFM3vDENmU=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 h1:bGeHBsGZx0Dvu/eJC0Lh9adJa3M1xREcndxLNZlve2U=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17/go.mod h1:dcW24lbU0CzHusTE8LLHhRLI42ejmINN8Lcr22bwh/g=
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0 h1:oeu8VPlOre74lBA/PMhxa5vewaMIMmILM+RraSyB8KA=
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0/go.mod h1:5jggDlZ2CLQhwJBiZJb4vfk4f0GxWdEDruWKEJ1xOdo=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 h1:VrhDvQib/i0lxvr3zqlUwLwJP4fpmpyD9wYG1vfSu+Y=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.5/go.mod h1:k029+U8SY30/3/ras4G/Fnv/b88N4mAfliNn08Dem4M=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 h1:v6EiMvhEYBoHABfbGB4alOYmCIrcgyPPiBE1wZAEbqk=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.9/go.mod h1:yifAsgBxgJWn3ggx70A3urX2AN49Y5sJTD1UQFlfqBw=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13 h1:gd84Omyu9JLriJVCbGApcLzVR3XtmC4ZDPcAI6Ftvds=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13/go.mod h1:sTGThjphYE4Ohw8vJiRStAcu3rbjtXRsdNB0TvZ5wwo=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 h1:5fFjR/ToSOzB2OQ/XqWpZBmNvmP/pJ1jOWYlFDJTjRQ=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6/go.mod h1:qgFDZQSD/Kys7nJnVqYlWKnh0SSdMjAi0uSwON4wgYQ=
github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk=
github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs=
github.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/casbin/casbin/v2 v2.135.0 h1:6BLkMQiGotYyS5yYeWgW19vxqugUlvHFkFiLnLR/bxk=
github.com/casbin/casbin/v2 v2.135.0/go.mod h1:FmcfntdXLTcYXv/hxgNntcRPqAbwOG9xsism0yXT+18=
github.com/casbin/govaluate v1.3.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A=
github.com/casbin/govaluate v1.10.0 h1:ffGw51/hYH3w3rZcxO/KcaUIDOLP84w7nsidMVgaDG0=
github.com/casbin/govaluate v1.10.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A=
github.com/casbin/mongodb-adapter/v4 v4.3.0 h1:yYXky9v1by6vj/0QK7OyHyd/xpz4vzh0lCi7JKrS4qQ=
github.com/casbin/mongodb-adapter/v4 v4.3.0/go.mod h1:bOTSYZUjX7I9E0ExEvgq46m3mcDNRII7g8iWjrM1BHE=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA=
github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI=
github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4=
github.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/jung-kurt/gofpdf v1.16.2 h1:jgbatWHfRlPYiK85qgevsZTHviWXKwB1TTiKdz5PtRc=
github.com/jung-kurt/gofpdf v1.16.2/go.mod h1:1hl7y57EsiPAkLbOwzpzqgx1A30nQCk/YmFV8S2vmK0=
github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw=
github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 h1:mFWunSatvkQQDhpdyuFAYwyAan3hzCuma+Pz8sqvOfg=
github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo=
github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/nats-io/nats.go v1.48.0 h1:pSFyXApG+yWU/TgbKCjmm5K4wrHu86231/w84qRVR+U=
github.com/nats-io/nats.go v1.48.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
github.com/nats-io/nkeys v0.4.15 h1:JACV5jRVO9V856KOapQ7x+EY8Jo3qw1vJt/9Jpwzkk4=
github.com/nats-io/nkeys v0.4.15/go.mod h1:CpMchTXC9fxA5zrMo4KpySxNjiDVvr8ANOSZdiNfUrs=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/phpdave11/gofpdi v1.0.7/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/testcontainers/testcontainers-go v0.33.0 h1:zJS9PfXYT5O0ZFXM2xxXfk4J5UMw/kRiISng037Gxdw=
github.com/testcontainers/testcontainers-go v0.33.0/go.mod h1:W80YpTa8D5C3Yy16icheD01UTDu+LmXIA2Keo+jWtT8=
github.com/testcontainers/testcontainers-go/modules/mongodb v0.33.0 h1:iXVA84s5hKMS5gn01GWOYHE3ymy/2b+0YkpFeTxB2XY=
github.com/testcontainers/testcontainers-go/modules/mongodb v0.33.0/go.mod h1:R6tMjTojRiaoo89fh/hf7tOmfzohdqSU17R9DwSVSog=
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.2.0 h1:bYKF2AEwG5rqd1BumT4gAnvwU/M9nBp2pTSxeZw7Wvs=
github.com/xdg-go/scram v1.2.0/go.mod h1:3dlrS0iBaWKYVt2ZfA4cj48umJZ+cAEbR6/SjLA88I8=
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF3xaE=
go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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-20260202165425-ce8ad4cf556b h1:GZxXGdFaHX27ZSMHudWc4FokdD+xl8BC2UJm1OVIEzs=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260202165425-ce8ad4cf556b/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
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=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -0,0 +1,28 @@
package appversion
import (
"github.com/tech/sendico/pkg/version"
vf "github.com/tech/sendico/pkg/version/factory"
)
// Build information populated at build time.
var (
Version string
Revision string
Branch string
BuildUser string
BuildDate string
)
// Create initialises a version.Printer with the build details for this service.
func Create() version.Printer {
info := version.Info{
Program: "Sendico Billing Documents Service",
Revision: Revision,
Branch: Branch,
BuildUser: BuildUser,
BuildDate: BuildDate,
Version: Version,
}
return vf.Create(&info)
}

View File

@@ -0,0 +1,61 @@
package docstore
import (
"context"
"os"
"path/filepath"
"strings"
"github.com/tech/sendico/pkg/merrors"
"github.com/tech/sendico/pkg/mlogger"
"go.uber.org/zap"
)
type LocalStore struct {
logger mlogger.Logger
rootPath string
}
func NewLocalStore(logger mlogger.Logger, cfg LocalConfig) (*LocalStore, error) {
root := strings.TrimSpace(cfg.RootPath)
if root == "" {
return nil, merrors.InvalidArgument("docstore: local root_path is empty")
}
store := &LocalStore{
logger: logger.Named("docstore").Named("local"),
rootPath: root,
}
store.logger.Info("Document storage initialised", zap.String("root_path", root))
return store, nil
}
func (s *LocalStore) Save(ctx context.Context, key string, data []byte) error {
if err := ctx.Err(); err != nil {
return err
}
path := filepath.Join(s.rootPath, filepath.Clean(key))
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
s.logger.Warn("Failed to create document directory", zap.Error(err), zap.String("path", path))
return err
}
if err := os.WriteFile(path, data, 0o600); err != nil {
s.logger.Warn("Failed to write document file", zap.Error(err), zap.String("path", path))
return err
}
return nil
}
func (s *LocalStore) Load(ctx context.Context, key string) ([]byte, error) {
if err := ctx.Err(); err != nil {
return nil, err
}
path := filepath.Join(s.rootPath, filepath.Clean(key))
data, err := os.ReadFile(path)
if err != nil {
s.logger.Warn("Failed to read document file", zap.Error(err), zap.String("path", path))
return nil, err
}
return data, nil
}
var _ Store = (*LocalStore)(nil)

View File

@@ -0,0 +1,125 @@
package docstore
import (
"bytes"
"context"
"io"
"os"
"strings"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/tech/sendico/pkg/merrors"
"github.com/tech/sendico/pkg/mlogger"
"go.uber.org/zap"
)
type S3Store struct {
logger mlogger.Logger
client *s3.Client
bucket string
}
func NewS3Store(logger mlogger.Logger, cfg S3Config) (*S3Store, error) {
bucket := strings.TrimSpace(cfg.Bucket)
if bucket == "" {
return nil, merrors.InvalidArgument("docstore: bucket is required")
}
accessKey := strings.TrimSpace(cfg.AccessKey)
if accessKey == "" && cfg.AccessKeyEnv != "" {
accessKey = strings.TrimSpace(os.Getenv(cfg.AccessKeyEnv))
}
secretKey := strings.TrimSpace(cfg.SecretAccessKey)
if secretKey == "" && cfg.SecretKeyEnv != "" {
secretKey = strings.TrimSpace(os.Getenv(cfg.SecretKeyEnv))
}
region := strings.TrimSpace(cfg.Region)
if region == "" {
region = "us-east-1"
}
loadOpts := []func(*config.LoadOptions) error{
config.WithRegion(region),
}
if accessKey != "" || secretKey != "" {
loadOpts = append(loadOpts, config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(
accessKey,
secretKey,
"",
)))
}
endpoint := strings.TrimSpace(cfg.Endpoint)
if endpoint != "" {
if !strings.HasPrefix(endpoint, "http://") && !strings.HasPrefix(endpoint, "https://") {
if cfg.UseSSL {
endpoint = "https://" + endpoint
} else {
endpoint = "http://" + endpoint
}
}
resolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, _ ...interface{}) (aws.Endpoint, error) {
if service == s3.ServiceID {
return aws.Endpoint{URL: endpoint, SigningRegion: region, HostnameImmutable: true}, nil
}
return aws.Endpoint{}, &aws.EndpointNotFoundError{}
})
loadOpts = append(loadOpts, config.WithEndpointResolverWithOptions(resolver))
}
awsCfg, err := config.LoadDefaultConfig(context.Background(), loadOpts...)
if err != nil {
logger.Warn("Failed to create AWS config", zap.Error(err), zap.String("bucket", bucket))
return nil, err
}
client := s3.NewFromConfig(awsCfg, func(opts *s3.Options) {
opts.UsePathStyle = cfg.ForcePathStyle
})
store := &S3Store{
logger: logger.Named("docstore").Named("s3"),
client: client,
bucket: bucket,
}
store.logger.Info("Document storage initialised", zap.String("bucket", bucket), zap.String("endpoint", endpoint))
return store, nil
}
func (s *S3Store) Save(ctx context.Context, key string, data []byte) error {
if err := ctx.Err(); err != nil {
return err
}
_, err := s.client.PutObject(ctx, &s3.PutObjectInput{
Bucket: aws.String(s.bucket),
Key: aws.String(key),
Body: bytes.NewReader(data),
})
if err != nil {
s.logger.Warn("Failed to upload document", zap.Error(err), zap.String("key", key))
return err
}
return nil
}
func (s *S3Store) Load(ctx context.Context, key string) ([]byte, error) {
if err := ctx.Err(); err != nil {
return nil, err
}
obj, err := s.client.GetObject(ctx, &s3.GetObjectInput{
Bucket: aws.String(s.bucket),
Key: aws.String(key),
})
if err != nil {
s.logger.Warn("Failed to fetch document", zap.Error(err), zap.String("key", key))
return nil, err
}
defer obj.Body.Close()
return io.ReadAll(obj.Body)
}
var _ Store = (*S3Store)(nil)

View File

@@ -0,0 +1,67 @@
package docstore
import (
"context"
"strings"
"github.com/tech/sendico/pkg/merrors"
"github.com/tech/sendico/pkg/mlogger"
)
// Driver identifies the document storage backend.
type Driver string
const (
DriverLocal Driver = "local_fs"
DriverS3 Driver = "s3"
DriverMinio Driver = "minio"
)
// Config configures the document storage backend.
type Config struct {
Driver Driver `yaml:"driver"`
Local *LocalConfig `yaml:"local"`
S3 *S3Config `yaml:"s3"`
}
// LocalConfig configures local filesystem storage.
type LocalConfig struct {
RootPath string `yaml:"root_path"`
}
// S3Config configures S3/Minio storage.
type S3Config struct {
Endpoint string `yaml:"endpoint"`
Region string `yaml:"region"`
Bucket string `yaml:"bucket"`
AccessKeyEnv string `yaml:"access_key_env"`
SecretKeyEnv string `yaml:"secret_access_key_env"`
AccessKey string `yaml:"access_key"`
SecretAccessKey string `yaml:"secret_access_key"`
UseSSL bool `yaml:"use_ssl"`
ForcePathStyle bool `yaml:"force_path_style"`
}
// Store defines storage operations for generated documents.
type Store interface {
Save(ctx context.Context, key string, data []byte) error
Load(ctx context.Context, key string) ([]byte, error)
}
// New creates a document store based on config.
func New(logger mlogger.Logger, cfg Config) (Store, error) {
switch strings.ToLower(string(cfg.Driver)) {
case string(DriverLocal):
if cfg.Local == nil {
return nil, merrors.InvalidArgument("docstore: local config missing")
}
return NewLocalStore(logger, *cfg.Local)
case string(DriverS3), string(DriverMinio):
if cfg.S3 == nil {
return nil, merrors.InvalidArgument("docstore: s3 config missing")
}
return NewS3Store(logger, *cfg.S3)
default:
return nil, merrors.InvalidArgument("docstore: unsupported driver")
}
}

View File

@@ -0,0 +1,144 @@
package serverimp
import (
"context"
"os"
"time"
"github.com/tech/sendico/billing/documents/internal/docstore"
"github.com/tech/sendico/billing/documents/internal/service/documents"
"github.com/tech/sendico/billing/documents/storage"
mongostorage "github.com/tech/sendico/billing/documents/storage/mongo"
"github.com/tech/sendico/pkg/api/routers"
"github.com/tech/sendico/pkg/db"
msg "github.com/tech/sendico/pkg/messaging"
"github.com/tech/sendico/pkg/mlogger"
"github.com/tech/sendico/pkg/server/grpcapp"
"go.uber.org/zap"
"gopkg.in/yaml.v3"
)
type Imp struct {
logger mlogger.Logger
file string
debug bool
config *config
app *grpcapp.App[storage.Repository]
service *documents.Service
}
type config struct {
*grpcapp.Config `yaml:",inline"`
Documents documents.Config `yaml:"documents"`
}
// Create initialises the billing documents server implementation.
func Create(logger mlogger.Logger, file string, debug bool) (*Imp, error) {
return &Imp{
logger: logger.Named("server"),
file: file,
debug: debug,
}, nil
}
func (i *Imp) Shutdown() {
if i.app == nil {
if i.service != nil {
i.service.Shutdown()
}
return
}
timeout := 15 * time.Second
if i.config != nil && i.config.Runtime != nil {
timeout = i.config.Runtime.ShutdownTimeout()
}
if i.service != nil {
i.service.Shutdown()
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
i.app.Shutdown(ctx)
cancel()
}
func (i *Imp) Start() error {
cfg, err := i.loadConfig()
if err != nil {
return err
}
i.config = cfg
repoFactory := func(logger mlogger.Logger, conn *db.MongoConnection) (storage.Repository, error) {
return mongostorage.New(logger, conn)
}
docStore, err := docstore.New(i.logger, cfg.Documents.Storage)
if err != nil {
i.logger.Error("Failed to initialise document storage", zap.Error(err))
return err
}
serviceFactory := func(logger mlogger.Logger, repo storage.Repository, producer msg.Producer) (grpcapp.Service, error) {
invokeURI := ""
if cfg.GRPC != nil {
invokeURI = cfg.GRPC.DiscoveryInvokeURI()
}
svc := documents.NewService(logger, repo, producer,
documents.WithDiscoveryInvokeURI(invokeURI),
documents.WithConfig(cfg.Documents),
documents.WithDocumentStore(docStore),
)
i.service = svc
return svc, nil
}
app, err := grpcapp.NewApp(i.logger, "billing_documents", cfg.Config, i.debug, repoFactory, serviceFactory)
if err != nil {
return err
}
i.app = app
return i.app.Start()
}
func (i *Imp) loadConfig() (*config, error) {
data, err := os.ReadFile(i.file)
if err != nil {
i.logger.Error("Could not read configuration file", zap.String("config_file", i.file), zap.Error(err))
return nil, err
}
cfg := &config{Config: &grpcapp.Config{}}
if err := yaml.Unmarshal(data, cfg); err != nil {
i.logger.Error("Failed to parse configuration", zap.Error(err))
return nil, err
}
if cfg.Runtime == nil {
cfg.Runtime = &grpcapp.RuntimeConfig{ShutdownTimeoutSeconds: 15}
}
if cfg.GRPC == nil {
cfg.GRPC = &routers.GRPCConfig{
Network: "tcp",
Address: ":50061",
EnableReflection: true,
EnableHealth: true,
}
}
if cfg.Metrics == nil {
cfg.Metrics = &grpcapp.MetricsConfig{Address: ":9409"}
}
if cfg.Documents.Storage.Driver == "" {
cfg.Documents.Storage.Driver = docstore.DriverLocal
if cfg.Documents.Storage.Local == nil {
cfg.Documents.Storage.Local = &docstore.LocalConfig{RootPath: "tmp/documents"}
}
}
return cfg, nil
}

View File

@@ -0,0 +1,12 @@
package server
import (
serverimp "github.com/tech/sendico/billing/documents/internal/server/internal"
"github.com/tech/sendico/pkg/mlogger"
"github.com/tech/sendico/pkg/server"
)
// Create constructs the billing documents server implementation.
func Create(logger mlogger.Logger, file string, debug bool) (server.Application, error) {
return serverimp.Create(logger, file, debug)
}

View File

@@ -0,0 +1,33 @@
package documents
import (
"strings"
"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"`
Templates TemplateConfig `yaml:"templates"`
Protection ProtectionConfig `yaml:"protection"`
Storage docstore.Config `yaml:"storage"`
}
// TemplateConfig defines document template locations.
type TemplateConfig struct {
AcceptancePath string `yaml:"acceptance_path"`
}
// ProtectionConfig configures PDF protection.
type ProtectionConfig struct {
OwnerPassword string `yaml:"owner_password"`
}
func (c Config) AcceptanceTemplatePath() string {
if strings.TrimSpace(c.Templates.AcceptancePath) == "" {
return "templates/acceptance.tpl"
}
return c.Templates.AcceptancePath
}

View File

@@ -0,0 +1,105 @@
package documents
import (
"strings"
"sync"
"time"
"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"
)
var (
metricsOnce sync.Once
requestsTotal *prometheus.CounterVec
requestLatency *prometheus.HistogramVec
batchSize prometheus.Histogram
documentBytes *prometheus.HistogramVec
)
func initMetrics() {
metricsOnce.Do(func() {
requestsTotal = promauto.NewCounterVec(
prometheus.CounterOpts{
Namespace: "billing",
Subsystem: "documents",
Name: "requests_total",
Help: "Total number of billing document requests processed.",
},
[]string{"call", "status", "doc_type"},
)
requestLatency = promauto.NewHistogramVec(
prometheus.HistogramOpts{
Namespace: "billing",
Subsystem: "documents",
Name: "request_latency_seconds",
Help: "Latency of billing document requests.",
Buckets: prometheus.DefBuckets,
},
[]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",
Subsystem: "documents",
Name: "document_bytes",
Help: "Size of generated billing document payloads.",
Buckets: prometheus.ExponentialBuckets(1024, 2, 10),
},
[]string{"doc_type"},
)
})
}
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 observeBatchSize(size int) {
batchSize.Observe(float64(size))
}
func observeDocumentBytes(docType documentsv1.DocumentType, size int) {
documentBytes.WithLabelValues(docTypeLabel(docType)).Observe(float64(size))
}
func statusFromError(err error) string {
if err == nil {
return "success"
}
st, ok := status.FromError(err)
if !ok {
return "error"
}
code := st.Code()
if code == codes.OK {
return "success"
}
return strings.ToLower(code.String())
}
func docTypeLabel(docType documentsv1.DocumentType) string {
label := docType.String()
if label == "" {
return "DOCUMENT_TYPE_UNSPECIFIED"
}
return label
}

View File

@@ -0,0 +1,418 @@
package documents
import (
"context"
"crypto/sha256"
"encoding/hex"
"errors"
"fmt"
"path/filepath"
"strings"
"time"
"github.com/tech/sendico/billing/documents/internal/appversion"
"github.com/tech/sendico/billing/documents/internal/docstore"
"github.com/tech/sendico/billing/documents/renderer"
"github.com/tech/sendico/billing/documents/storage"
"github.com/tech/sendico/billing/documents/storage/model"
"github.com/tech/sendico/pkg/api/routers"
"github.com/tech/sendico/pkg/discovery"
msg "github.com/tech/sendico/pkg/messaging"
"github.com/tech/sendico/pkg/mlogger"
"github.com/tech/sendico/pkg/mservice"
documentsv1 "github.com/tech/sendico/pkg/proto/billing/documents/v1"
"go.uber.org/zap"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// TemplateRenderer renders the acceptance template into tagged blocks.
type TemplateRenderer interface {
Render(snapshot model.ActSnapshot) ([]renderer.Block, error)
}
// Option configures the documents service.
type Option func(*Service)
// WithDiscoveryInvokeURI configures the discovery invoke URI.
func WithDiscoveryInvokeURI(uri string) Option {
return func(s *Service) {
if s == nil {
return
}
s.invokeURI = strings.TrimSpace(uri)
}
}
// WithProducer sets the messaging producer.
func WithProducer(producer msg.Producer) Option {
return func(s *Service) {
if s == nil {
return
}
s.producer = producer
}
}
// WithConfig sets the service config.
func WithConfig(cfg Config) Option {
return func(s *Service) {
if s == nil {
return
}
s.config = cfg
}
}
// WithDocumentStore sets the document storage backend.
func WithDocumentStore(store docstore.Store) Option {
return func(s *Service) {
if s == nil {
return
}
s.docStore = store
}
}
// WithTemplateRenderer overrides the template renderer (useful for tests).
func WithTemplateRenderer(renderer TemplateRenderer) Option {
return func(s *Service) {
if s == nil {
return
}
s.template = renderer
}
}
// Service provides billing document metadata and retrieval endpoints.
type Service struct {
logger mlogger.Logger
storage storage.Repository
docStore docstore.Store
producer msg.Producer
announcer *discovery.Announcer
invokeURI string
config Config
template TemplateRenderer
documentsv1.UnimplementedDocumentServiceServer
}
// NewService constructs a documents service with optional configuration.
func NewService(logger mlogger.Logger, repo storage.Repository, producer msg.Producer, opts ...Option) *Service {
initMetrics()
svc := &Service{
logger: logger.Named("documents"),
storage: repo,
producer: producer,
}
for _, opt := range opts {
opt(svc)
}
if svc.template == nil {
if tmpl, err := newTemplateRenderer(svc.config.AcceptanceTemplatePath()); err != nil {
svc.logger.Warn("failed to load acceptance template", zap.Error(err))
} else {
svc.template = tmpl
}
}
svc.startDiscoveryAnnouncer()
return svc
}
func (s *Service) Register(router routers.GRPC) error {
return router.Register(func(reg grpc.ServiceRegistrar) {
documentsv1.RegisterDocumentServiceServer(reg, s)
})
}
func (s *Service) Shutdown() {
if s == nil {
return
}
if s.announcer != nil {
s.announcer.Stop()
}
}
func (s *Service) startDiscoveryAnnouncer() {
if s == nil || s.producer == nil {
return
}
announce := discovery.Announcement{
Service: "BILLING_DOCUMENTS",
Operations: []string{"documents.batch_resolve", "documents.get"},
InvokeURI: s.invokeURI,
Version: appversion.Create().Short(),
}
s.announcer = discovery.NewAnnouncer(s.logger, s.producer, string(mservice.BillingDocuments), announce)
s.announcer.Start()
}
func (s *Service) BatchResolveDocuments(ctx context.Context, req *documentsv1.BatchResolveDocumentsRequest) (resp *documentsv1.BatchResolveDocumentsResponse, err error) {
start := time.Now()
var paymentRefs []string
if req != nil {
paymentRefs = req.GetPaymentRefs()
}
logger := s.logger.With(zap.Int("payment_refs", len(paymentRefs)))
defer func() {
statusLabel := statusFromError(err)
observeRequest("batch_resolve", documentsv1.DocumentType_DOCUMENT_TYPE_UNSPECIFIED, statusLabel, time.Since(start))
observeBatchSize(len(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...)
}()
if len(paymentRefs) == 0 {
resp = &documentsv1.BatchResolveDocumentsResponse{}
return resp, nil
}
if s.storage == nil {
err = status.Error(codes.Unavailable, errStorageUnavailable.Error())
return nil, err
}
refs := make([]string, 0, len(paymentRefs))
for _, ref := range paymentRefs {
clean := strings.TrimSpace(ref)
if clean == "" {
continue
}
refs = append(refs, clean)
}
if len(refs) == 0 {
resp = &documentsv1.BatchResolveDocumentsResponse{}
return resp, nil
}
records, err := s.storage.Documents().ListByPaymentRefs(ctx, refs)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
recordByRef := map[string]*model.DocumentRecord{}
for _, record := range records {
if record == nil {
continue
}
recordByRef[record.PaymentRef] = record
}
items := make([]*documentsv1.DocumentMeta, 0, len(refs))
for _, ref := range refs {
meta := &documentsv1.DocumentMeta{PaymentRef: ref}
if record := recordByRef[ref]; record != nil {
record.Normalize()
available := []model.DocumentType{model.DocumentTypeAct}
ready := make([]model.DocumentType, 0, 1)
if path, ok := record.StoragePaths[model.DocumentTypeAct]; ok && path != "" {
ready = append(ready, model.DocumentTypeAct)
}
meta.AvailableTypes = toProtoTypes(available)
meta.ReadyTypes = toProtoTypes(ready)
}
items = append(items, meta)
}
resp = &documentsv1.BatchResolveDocumentsResponse{Items: items}
return resp, nil
}
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...)
}()
if paymentRef == "" {
err = status.Error(codes.InvalidArgument, "payment_ref is required")
return nil, err
}
if docType == documentsv1.DocumentType_DOCUMENT_TYPE_UNSPECIFIED {
err = status.Error(codes.InvalidArgument, "document type is required")
return nil, err
}
if s.storage == nil {
err = status.Error(codes.Unavailable, errStorageUnavailable.Error())
return nil, err
}
if s.docStore == nil {
err = status.Error(codes.Unavailable, errDocStoreUnavailable.Error())
return nil, err
}
if s.template == nil {
err = status.Error(codes.FailedPrecondition, errTemplateUnavailable.Error())
return nil, err
}
record, err := s.storage.Documents().GetByPaymentRef(ctx, paymentRef)
if err != nil {
if errors.Is(err, storage.ErrDocumentNotFound) {
return nil, status.Error(codes.NotFound, "document record not found")
}
return nil, status.Error(codes.Internal, err.Error())
}
record.Normalize()
targetType := model.DocumentTypeFromProto(docType)
if docType != documentsv1.DocumentType_DOCUMENT_TYPE_ACT {
return nil, status.Error(codes.Unimplemented, "document type not implemented")
}
if path, ok := record.StoragePaths[targetType]; ok && path != "" {
content, loadErr := s.docStore.Load(ctx, path)
if loadErr != nil {
return nil, status.Error(codes.Internal, loadErr.Error())
}
return &documentsv1.GetDocumentResponse{
Content: content,
Filename: documentFilename(docType, paymentRef),
MimeType: "application/pdf",
}, nil
}
content, hash, genErr := s.generateActPDF(record.Snapshot)
if genErr != nil {
logger.Warn("Failed to generate document", zap.Error(genErr))
return nil, status.Error(codes.Internal, genErr.Error())
}
path := documentStoragePath(paymentRef, docType)
if saveErr := s.docStore.Save(ctx, path, content); saveErr != nil {
logger.Warn("Failed to store document", zap.Error(saveErr))
return nil, status.Error(codes.Internal, saveErr.Error())
}
record.StoragePaths[targetType] = path
record.Hashes[targetType] = hash
if updateErr := s.storage.Documents().Update(ctx, record); updateErr != nil {
logger.Warn("Failed to update document record", zap.Error(updateErr))
return nil, status.Error(codes.Internal, updateErr.Error())
}
resp = &documentsv1.GetDocumentResponse{
Content: content,
Filename: documentFilename(docType, paymentRef),
MimeType: "application/pdf",
}
return resp, nil
}
type serviceError string
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 {
return nil, "", err
}
generated := renderer.Renderer{
Issuer: s.config.Issuer,
OwnerPassword: s.config.Protection.OwnerPassword,
}
placeholder := strings.Repeat("0", 64)
firstPass, err := generated.Render(blocks, placeholder)
if err != nil {
return nil, "", err
}
footerHash := sha256.Sum256(firstPass)
footerHex := hex.EncodeToString(footerHash[:])
finalBytes, err := generated.Render(blocks, footerHex)
if err != nil {
return nil, "", err
}
return finalBytes, footerHex, nil
}
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"
}
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"
}
return fmt.Sprintf("%s_%s.pdf", name, paymentRef)
}

View File

@@ -0,0 +1,195 @@
package documents
import (
"bytes"
"context"
"testing"
"time"
"github.com/shopspring/decimal"
"github.com/tech/sendico/billing/documents/renderer"
"github.com/tech/sendico/billing/documents/storage"
"github.com/tech/sendico/billing/documents/storage/model"
documentsv1 "github.com/tech/sendico/pkg/proto/billing/documents/v1"
"go.uber.org/zap"
)
type stubRepo struct {
store storage.DocumentsStore
}
func (s *stubRepo) Ping(ctx context.Context) error { return nil }
func (s *stubRepo) Documents() storage.DocumentsStore { return s.store }
var _ storage.Repository = (*stubRepo)(nil)
type stubDocumentsStore struct {
record *model.DocumentRecord
updateCalls int
}
func (s *stubDocumentsStore) Create(ctx context.Context, record *model.DocumentRecord) error {
s.record = record
return nil
}
func (s *stubDocumentsStore) Update(ctx context.Context, record *model.DocumentRecord) error {
s.record = record
s.updateCalls++
return nil
}
func (s *stubDocumentsStore) GetByPaymentRef(ctx context.Context, paymentRef string) (*model.DocumentRecord, error) {
return s.record, nil
}
func (s *stubDocumentsStore) ListByPaymentRefs(ctx context.Context, paymentRefs []string) ([]*model.DocumentRecord, error) {
return []*model.DocumentRecord{s.record}, nil
}
var _ storage.DocumentsStore = (*stubDocumentsStore)(nil)
type memDocStore struct {
data map[string][]byte
saveCount int
loadCount int
}
func newMemDocStore() *memDocStore {
return &memDocStore{data: map[string][]byte{}}
}
func (m *memDocStore) Save(ctx context.Context, key string, data []byte) error {
m.saveCount++
copyData := make([]byte, len(data))
copy(copyData, data)
m.data[key] = copyData
return nil
}
func (m *memDocStore) Load(ctx context.Context, key string) ([]byte, error) {
m.loadCount++
data := m.data[key]
copyData := make([]byte, len(data))
copy(copyData, data)
return copyData, nil
}
func (m *memDocStore) Counts() (int, int) {
return m.saveCount, m.loadCount
}
type stubTemplate struct {
blocks []renderer.Block
calls int
}
func (s *stubTemplate) Render(snapshot model.ActSnapshot) ([]renderer.Block, error) {
s.calls++
return s.blocks, nil
}
func TestGetDocument_IdempotentAndHashed(t *testing.T) {
ctx := context.Background()
snapshot := model.ActSnapshot{
PaymentID: "PAY-123",
Date: time.Date(2026, 1, 30, 0, 0, 0, 0, time.UTC),
ExecutorFullName: "Jane Doe",
Amount: decimal.RequireFromString("100.00"),
Currency: "USD",
}
record := &model.DocumentRecord{
PaymentRef: "PAY-123",
Snapshot: snapshot,
}
documentsStore := &stubDocumentsStore{record: record}
repo := &stubRepo{store: documentsStore}
store := newMemDocStore()
tmpl := &stubTemplate{
blocks: []renderer.Block{
{Tag: renderer.TagTitle, Lines: []string{"ACT"}},
{Tag: renderer.TagText, Lines: []string{"Executor: Jane Doe", "Amount: 100 USD"}},
},
}
cfg := Config{
Issuer: renderer.Issuer{
LegalName: "Sendico Ltd",
LegalAddress: "12 Market Street, London, UK",
},
}
svc := NewService(zap.NewNop(), repo, nil,
WithConfig(cfg),
WithDocumentStore(store),
WithTemplateRenderer(tmpl),
)
resp1, err := svc.GetDocument(ctx, &documentsv1.GetDocumentRequest{
PaymentRef: "PAY-123",
Type: documentsv1.DocumentType_DOCUMENT_TYPE_ACT,
})
if err != nil {
t.Fatalf("GetDocument first call: %v", err)
}
if len(resp1.Content) == 0 {
t.Fatalf("expected content on first call")
}
stored := record.Hashes[model.DocumentTypeAct]
if stored == "" {
t.Fatalf("expected stored hash")
}
footerHash := extractFooterHash(resp1.Content)
if footerHash == "" {
t.Fatalf("expected footer hash in PDF")
}
if stored != footerHash {
t.Fatalf("stored hash mismatch: got %s", stored)
}
resp2, err := svc.GetDocument(ctx, &documentsv1.GetDocumentRequest{
PaymentRef: "PAY-123",
Type: documentsv1.DocumentType_DOCUMENT_TYPE_ACT,
})
if err != nil {
t.Fatalf("GetDocument second call: %v", err)
}
if !bytes.Equal(resp1.Content, resp2.Content) {
t.Fatalf("expected identical PDF bytes on second call")
}
if tmpl.calls != 1 {
t.Fatalf("expected template to be rendered once, got %d", tmpl.calls)
}
if store.saveCount != 1 {
t.Fatalf("expected document save once, got %d", store.saveCount)
}
if store.loadCount == 0 {
t.Fatalf("expected document load on second call")
}
}
func extractFooterHash(pdf []byte) string {
prefix := []byte("Document integrity hash: ")
idx := bytes.Index(pdf, prefix)
if idx == -1 {
return ""
}
start := idx + len(prefix)
end := start
for end < len(pdf) && isHexDigit(pdf[end]) {
end++
}
if end-start != 64 {
return ""
}
return string(pdf[start:end])
}
func isHexDigit(b byte) bool {
return (b >= '0' && b <= '9') || (b >= 'a' && b <= 'f') || (b >= 'A' && b <= 'F')
}

View File

@@ -0,0 +1,60 @@
package documents
import (
"bytes"
"fmt"
"os"
"strings"
"text/template"
"time"
"github.com/shopspring/decimal"
"github.com/tech/sendico/billing/documents/renderer"
"github.com/tech/sendico/billing/documents/storage/model"
)
type templateRenderer struct {
tpl *template.Template
}
func newTemplateRenderer(path string) (*templateRenderer, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("read template: %w", err)
}
funcs := template.FuncMap{
"money": formatMoney,
"date": formatDate,
}
tpl, err := template.New("acceptance").Funcs(funcs).Option("missingkey=error").Parse(string(data))
if err != nil {
return nil, fmt.Errorf("parse template: %w", err)
}
return &templateRenderer{tpl: tpl}, nil
}
func (r *templateRenderer) Render(snapshot model.ActSnapshot) ([]renderer.Block, error) {
var buf bytes.Buffer
if err := r.tpl.Execute(&buf, snapshot); err != nil {
return nil, fmt.Errorf("execute template: %w", err)
}
return renderer.ParseBlocks(buf.String())
}
func formatMoney(amount decimal.Decimal, currency string) string {
currency = strings.TrimSpace(currency)
if currency == "" {
return amount.String()
}
return fmt.Sprintf("%s %s", amount.String(), currency)
}
func formatDate(t time.Time) string {
if t.IsZero() {
return ""
}
return t.Format("2006-01-02")
}

View File

@@ -0,0 +1,89 @@
package documents
import (
"path/filepath"
"testing"
"time"
"github.com/shopspring/decimal"
"github.com/tech/sendico/billing/documents/renderer"
"github.com/tech/sendico/billing/documents/storage/model"
)
func TestTemplateRenderer_Render(t *testing.T) {
path := filepath.Join("..", "..", "..", "templates", "acceptance.tpl")
tmpl, err := newTemplateRenderer(path)
if err != nil {
t.Fatalf("newTemplateRenderer: %v", err)
}
snapshot := model.ActSnapshot{
PaymentID: "PAY-001",
Date: time.Date(2026, 1, 30, 0, 0, 0, 0, time.UTC),
ExecutorFullName: "Jane Doe",
Amount: decimal.RequireFromString("123.45"),
Currency: "USD",
}
blocks, err := tmpl.Render(snapshot)
if err != nil {
t.Fatalf("Render: %v", err)
}
if len(blocks) == 0 {
t.Fatalf("expected blocks, got none")
}
title := findBlock(blocks, renderer.TagTitle)
if title == nil {
t.Fatalf("expected title block")
}
foundTitle := false
for _, line := range title.Lines {
if line == "ACT OF ACCEPTANCE OF SERVICES" {
foundTitle = true
break
}
}
if !foundTitle {
t.Fatalf("expected title content not found")
}
kv := findBlock(blocks, renderer.TagKV)
if kv == nil {
t.Fatalf("expected kv block")
}
foundExecutor := false
for _, row := range kv.Rows {
if len(row) >= 2 && row[0] == "Executor" && row[1] == snapshot.ExecutorFullName {
foundExecutor = true
break
}
}
if !foundExecutor {
t.Fatalf("expected executor name in kv block")
}
table := findBlock(blocks, renderer.TagTable)
if table == nil {
t.Fatalf("expected table block")
}
foundAmount := false
for _, row := range table.Rows {
if len(row) >= 2 && row[1] == "123.45 USD" {
foundAmount = true
break
}
}
if !foundAmount {
t.Fatalf("expected amount in table block")
}
}
func findBlock(blocks []renderer.Block, tag renderer.Tag) *renderer.Block {
for i := range blocks {
if blocks[i].Tag == tag {
return &blocks[i]
}
}
return nil
}

View File

@@ -0,0 +1,17 @@
package main
import (
"github.com/tech/sendico/billing/documents/internal/appversion"
si "github.com/tech/sendico/billing/documents/internal/server"
"github.com/tech/sendico/pkg/mlogger"
"github.com/tech/sendico/pkg/server"
smain "github.com/tech/sendico/pkg/server/main"
)
func factory(logger mlogger.Logger, file string, debug bool) (server.Application, error) {
return si.Create(logger, file, debug)
}
func main() {
smain.RunServer("main", appversion.Create(), factory)
}

View File

@@ -0,0 +1,50 @@
package renderer
import (
"strings"
"github.com/jung-kurt/gofpdf"
)
// Issuer describes the document issuer.
type Issuer struct {
LegalName string `yaml:"legal_name"`
LegalAddress string `yaml:"legal_address"`
LogoPath string `yaml:"logo_path"`
}
func drawHeader(pdf *gofpdf.Fpdf, issuer Issuer, marginLeft, marginTop float64) (float64, error) {
startX := marginLeft
startY := marginTop
logoWidth := 0.0
if strings.TrimSpace(issuer.LogoPath) != "" {
logoWidth = 24
pdf.ImageOptions(issuer.LogoPath, startX, startY, logoWidth, 0, false, gofpdf.ImageOptions{ReadDpi: true}, 0, "")
}
textX := startX
if logoWidth > 0 {
textX = startX + logoWidth + 6
}
pdf.SetXY(textX, startY)
pdf.SetFont("Helvetica", "B", 12)
pdf.CellFormat(0, 5, issuer.LegalName, "", 1, "L", false, 0, "")
pdf.SetX(textX)
pdf.SetFont("Helvetica", "", 10)
pdf.MultiCell(0, 4.5, issuer.LegalAddress, "", "L", false)
if pdf.Error() != nil {
return 0, pdf.Error()
}
currentY := pdf.GetY()
if logoWidth > 0 {
logoBottom := startY + logoWidth
if logoBottom > currentY {
currentY = logoBottom
}
}
return currentY - startY, nil
}

View File

@@ -0,0 +1,221 @@
package renderer
import (
"bytes"
"fmt"
"math"
"strings"
"github.com/jung-kurt/gofpdf"
)
const (
pageMarginLeft = 20.0
pageMarginRight = 20.0
pageMarginTop = 20.0
pageMarginBottom = 22.0
)
// Renderer builds a PDF document from tagged blocks.
type Renderer struct {
Issuer Issuer
OwnerPassword string
}
// Render generates the PDF bytes for the provided blocks and footer hash.
func (r Renderer) Render(blocks []Block, footerHash string) ([]byte, error) {
pdf := gofpdf.New("P", "mm", "A4", "")
pdf.SetMargins(pageMarginLeft, pageMarginTop, pageMarginRight)
pdf.SetAutoPageBreak(true, pageMarginBottom)
pdf.SetCompression(false)
pdf.SetAuthor(r.Issuer.LegalName, false)
pdf.SetTitle("Act of Acceptance", false)
owner := strings.TrimSpace(r.OwnerPassword)
if owner != "" {
pdf.SetProtection(gofpdf.CnProtectPrint, "", owner)
}
pdf.SetFooterFunc(func() {
pdf.SetY(-15)
pdf.SetFont("Helvetica", "", 8)
footer := fmt.Sprintf("Document integrity hash: %s", footerHash)
pdf.CellFormat(0, 5, footer, "", 0, "L", false, 0, "")
})
pdf.AddPage()
if _, err := drawHeader(pdf, r.Issuer, pageMarginLeft, pageMarginTop); err != nil {
return nil, err
}
pdf.Ln(6)
for _, block := range blocks {
renderBlock(pdf, block)
if pdf.Error() != nil {
return nil, pdf.Error()
}
}
buf := &bytes.Buffer{}
if err := pdf.Output(buf); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func renderBlock(pdf *gofpdf.Fpdf, block Block) {
switch block.Tag {
case TagSpacer:
pdf.Ln(6)
case TagTitle:
pdf.SetFont("Helvetica", "B", 14)
for _, line := range block.Lines {
if strings.TrimSpace(line) == "" {
pdf.Ln(4)
continue
}
pdf.CellFormat(0, 7, line, "", 1, "C", false, 0, "")
}
pdf.Ln(2)
case TagSubtitle:
pdf.SetFont("Helvetica", "", 11)
for _, line := range block.Lines {
if strings.TrimSpace(line) == "" {
pdf.Ln(3)
continue
}
pdf.CellFormat(0, 6, line, "", 1, "C", false, 0, "")
}
pdf.Ln(2)
case TagMeta:
pdf.SetFont("Helvetica", "", 9)
for _, line := range block.Lines {
if strings.TrimSpace(line) == "" {
pdf.Ln(2)
continue
}
pdf.CellFormat(0, 4.5, line, "", 1, "R", false, 0, "")
}
pdf.Ln(2)
case TagSection:
pdf.Ln(2)
pdf.SetFont("Helvetica", "B", 11)
for _, line := range block.Lines {
if strings.TrimSpace(line) == "" {
pdf.Ln(3)
continue
}
pdf.CellFormat(0, 6, line, "", 1, "L", false, 0, "")
}
pdf.Ln(1)
case TagText:
pdf.SetFont("Helvetica", "", 10)
text := strings.Join(block.Lines, "\n")
pdf.MultiCell(0, 5, text, "", "L", false)
pdf.Ln(1)
case TagKV:
renderKeyValue(pdf, block)
case TagTable:
renderTable(pdf, block)
case TagSign:
pdf.SetFont("Helvetica", "", 10)
text := strings.Join(block.Lines, "\n")
pdf.MultiCell(0, 6, text, "", "L", false)
pdf.Ln(2)
default:
// Unknown tag: treat as plain text for resilience.
pdf.SetFont("Helvetica", "", 10)
text := strings.Join(block.Lines, "\n")
pdf.MultiCell(0, 5, text, "", "L", false)
pdf.Ln(1)
}
}
func renderKeyValue(pdf *gofpdf.Fpdf, block Block) {
pdf.SetFont("Helvetica", "", 10)
usable := usableWidth(pdf)
keyWidth := math.Round(usable * 0.35)
valueWidth := usable - keyWidth
lineHeight := 5.0
for _, row := range block.Rows {
if len(row) == 0 {
continue
}
key := row[0]
value := ""
if len(row) > 1 {
value = row[1]
}
x := pdf.GetX()
y := pdf.GetY()
pdf.SetXY(x, y)
pdf.SetFont("Helvetica", "B", 10)
pdf.MultiCell(keyWidth, lineHeight, key, "", "L", false)
leftY := pdf.GetY()
pdf.SetXY(x+keyWidth, y)
pdf.SetFont("Helvetica", "", 10)
pdf.MultiCell(valueWidth, lineHeight, value, "", "L", false)
rightY := pdf.GetY()
pdf.SetY(maxFloat(leftY, rightY))
}
pdf.Ln(1)
}
func renderTable(pdf *gofpdf.Fpdf, block Block) {
if len(block.Rows) == 0 {
return
}
usable := usableWidth(pdf)
col1 := math.Round(usable * 0.7)
col2 := usable - col1
lineHeight := 6.0
header := block.Rows[0]
pdf.SetFont("Helvetica", "B", 10)
if len(header) > 0 {
pdf.CellFormat(col1, lineHeight, header[0], "1", 0, "L", false, 0, "")
}
if len(header) > 1 {
pdf.CellFormat(col2, lineHeight, header[1], "1", 1, "R", false, 0, "")
} else {
pdf.CellFormat(col2, lineHeight, "", "1", 1, "R", false, 0, "")
}
pdf.SetFont("Helvetica", "", 10)
for _, row := range block.Rows[1:] {
colA := ""
colB := ""
if len(row) > 0 {
colA = row[0]
}
if len(row) > 1 {
colB = row[1]
}
x := pdf.GetX()
y := pdf.GetY()
pdf.MultiCell(col1, lineHeight, colA, "1", "L", false)
leftY := pdf.GetY()
pdf.SetXY(x+col1, y)
pdf.MultiCell(col2, lineHeight, colB, "1", "R", false)
rightY := pdf.GetY()
pdf.SetY(maxFloat(leftY, rightY))
}
pdf.Ln(2)
}
func usableWidth(pdf *gofpdf.Fpdf) float64 {
pageW, _ := pdf.GetPageSize()
left, _, right, _ := pdf.GetMargins()
return pageW - left - right
}
func maxFloat(a, b float64) float64 {
if a > b {
return a
}
return b
}

View File

@@ -0,0 +1,90 @@
package renderer
import (
"bytes"
"encoding/hex"
"strings"
"testing"
"unicode/utf16"
)
func TestRenderer_RenderContainsText(t *testing.T) {
blocks := []Block{
{Tag: TagTitle, Lines: []string{"ACT"}},
{Tag: TagText, Lines: []string{"Executor: Jane Doe", "Amount: 100 USD"}},
}
r := Renderer{
Issuer: Issuer{
LegalName: "Sendico Ltd",
LegalAddress: "12 Market Street, London, UK",
},
OwnerPassword: "",
}
pdfBytes, err := r.Render(blocks, "deadbeef")
if err != nil {
t.Fatalf("Render: %v", err)
}
if len(pdfBytes) == 0 {
t.Fatalf("expected PDF bytes")
}
checks := []string{"Sendico Ltd", "Jane Doe", "100 USD", "Document integrity hash"}
for _, token := range checks {
if !containsPDFText(pdfBytes, token) {
t.Fatalf("expected PDF to contain %q", token)
}
}
}
func containsPDFText(pdfBytes []byte, text string) bool {
if bytes.Contains(pdfBytes, []byte(text)) {
return true
}
hexText := hex.EncodeToString([]byte(text))
if bytes.Contains(pdfBytes, []byte(strings.ToUpper(hexText))) {
return true
}
if bytes.Contains(pdfBytes, []byte(strings.ToLower(hexText))) {
return true
}
utf16Bytes := encodeUTF16BE(text, false)
if bytes.Contains(pdfBytes, utf16Bytes) {
return true
}
utf16Hex := hex.EncodeToString(utf16Bytes)
if bytes.Contains(pdfBytes, []byte(strings.ToUpper(utf16Hex))) {
return true
}
if bytes.Contains(pdfBytes, []byte(strings.ToLower(utf16Hex))) {
return true
}
utf16BytesBOM := encodeUTF16BE(text, true)
if bytes.Contains(pdfBytes, utf16BytesBOM) {
return true
}
utf16HexBOM := hex.EncodeToString(utf16BytesBOM)
if bytes.Contains(pdfBytes, []byte(strings.ToUpper(utf16HexBOM))) {
return true
}
return bytes.Contains(pdfBytes, []byte(strings.ToLower(utf16HexBOM)))
}
func encodeUTF16BE(text string, withBOM bool) []byte {
encoded := utf16.Encode([]rune(text))
length := len(encoded) * 2
if withBOM {
length += 2
}
out := make([]byte, 0, length)
if withBOM {
out = append(out, 0xFE, 0xFF)
}
for _, v := range encoded {
out = append(out, byte(v>>8), byte(v))
}
return out
}

View File

@@ -0,0 +1,87 @@
package renderer
import (
"bufio"
"fmt"
"strings"
)
// Tag defines supported template blocks.
type Tag string
const (
TagSpacer Tag = "spacer"
TagTitle Tag = "title"
TagSubtitle Tag = "subtitle"
TagMeta Tag = "meta"
TagSection Tag = "section"
TagText Tag = "text"
TagKV Tag = "kv"
TagTable Tag = "table"
TagSign Tag = "sign"
)
// Block represents a tagged content block extracted from template output.
type Block struct {
Tag Tag
Lines []string
Rows [][]string
}
// ParseBlocks converts tagged template output into structured blocks.
func ParseBlocks(input string) ([]Block, error) {
scanner := bufio.NewScanner(strings.NewReader(input))
blocks := make([]Block, 0)
var current *Block
flush := func() {
if current != nil {
blocks = append(blocks, *current)
current = nil
}
}
for scanner.Scan() {
line := strings.TrimRight(scanner.Text(), "\r")
trimmed := strings.TrimSpace(line)
if strings.HasPrefix(trimmed, "#") {
flush()
tag := Tag(strings.TrimSpace(strings.TrimPrefix(trimmed, "#")))
if tag == "" {
continue
}
if tag == TagSpacer {
blocks = append(blocks, Block{Tag: TagSpacer})
continue
}
current = &Block{Tag: tag}
continue
}
if current == nil {
continue
}
switch current.Tag {
case TagKV, TagTable:
if trimmed == "" {
continue
}
parts := strings.Split(line, "|")
row := make([]string, 0, len(parts))
for _, part := range parts {
row = append(row, strings.TrimSpace(part))
}
current.Rows = append(current.Rows, row)
default:
current.Lines = append(current.Lines, line)
}
}
if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("parse blocks: %w", err)
}
flush()
return blocks, nil
}

View File

@@ -0,0 +1,86 @@
package model
import (
"strings"
"time"
"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.
type DocumentType string
const (
DocumentTypeUnspecified DocumentType = "DOCUMENT_TYPE_UNSPECIFIED"
DocumentTypeInvoice DocumentType = "DOCUMENT_TYPE_INVOICE"
DocumentTypeAct DocumentType = "DOCUMENT_TYPE_ACT"
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"`
Date time.Time `bson:"date" json:"date"`
ExecutorFullName string `bson:"executorFullName" json:"executorFullName"`
Amount decimal.Decimal `bson:"amount" json:"amount"`
Currency string `bson:"currency" json:"currency"`
}
func (s *ActSnapshot) Normalize() {
if s == nil {
return
}
s.PaymentID = strings.TrimSpace(s.PaymentID)
s.ExecutorFullName = strings.TrimSpace(s.ExecutorFullName)
s.Currency = strings.TrimSpace(s.Currency)
}
// DocumentRecord stores document metadata and cached artefacts for a payment.
type DocumentRecord struct {
storable.Base `bson:",inline" json:",inline"`
PaymentRef string `bson:"paymentRef" json:"paymentRef"`
Snapshot ActSnapshot `bson:"snapshot" json:"snapshot"`
StoragePaths map[DocumentType]string `bson:"storagePaths,omitempty" json:"storagePaths,omitempty"`
Hashes map[DocumentType]string `bson:"hashes,omitempty" json:"hashes,omitempty"`
}
func (r *DocumentRecord) Normalize() {
if r == nil {
return
}
r.PaymentRef = strings.TrimSpace(r.PaymentRef)
r.Snapshot.Normalize()
if r.StoragePaths == nil {
r.StoragePaths = map[DocumentType]string{}
}
if r.Hashes == nil {
r.Hashes = map[DocumentType]string{}
}
}
// Collection implements storable.Storable.
func (*DocumentRecord) Collection() string {
return DocumentRecordsCollection
}

View File

@@ -0,0 +1,68 @@
package mongo
import (
"context"
"time"
"github.com/tech/sendico/billing/documents/storage"
"github.com/tech/sendico/billing/documents/storage/mongo/store"
"github.com/tech/sendico/pkg/db"
"github.com/tech/sendico/pkg/merrors"
"github.com/tech/sendico/pkg/mlogger"
"go.mongodb.org/mongo-driver/v2/mongo"
"go.uber.org/zap"
)
type Store struct {
logger mlogger.Logger
conn *db.MongoConnection
db *mongo.Database
documents storage.DocumentsStore
}
// New creates a repository backed by MongoDB for the billing documents service.
func New(logger mlogger.Logger, conn *db.MongoConnection) (*Store, error) {
if conn == nil {
return nil, merrors.InvalidArgument("mongo connection is nil")
}
client := conn.Client()
if client == nil {
return nil, merrors.Internal("mongo client not initialised")
}
database := conn.Database()
result := &Store{
logger: logger.Named("storage").Named("mongo"),
conn: conn,
db: database,
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := result.Ping(ctx); err != nil {
result.logger.Error("mongo ping failed during store init", zap.Error(err))
return nil, err
}
documentsStore, err := store.NewDocuments(result.logger, database)
if err != nil {
result.logger.Error("failed to initialise documents store", zap.Error(err))
return nil, err
}
result.documents = documentsStore
result.logger.Info("Billing documents MongoDB storage initialised")
return result, nil
}
func (s *Store) Ping(ctx context.Context) error {
return s.conn.Ping(ctx)
}
func (s *Store) Documents() storage.DocumentsStore {
return s.documents
}
var _ storage.Repository = (*Store)(nil)

View File

@@ -0,0 +1,139 @@
package store
import (
"context"
"errors"
"strings"
"github.com/tech/sendico/billing/documents/storage"
"github.com/tech/sendico/billing/documents/storage/model"
"github.com/tech/sendico/pkg/db/repository"
"github.com/tech/sendico/pkg/db/repository/builder"
ri "github.com/tech/sendico/pkg/db/repository/index"
"github.com/tech/sendico/pkg/merrors"
"github.com/tech/sendico/pkg/mlogger"
"go.mongodb.org/mongo-driver/v2/mongo"
"go.uber.org/zap"
)
type Documents struct {
logger mlogger.Logger
repo repository.Repository
}
// NewDocuments constructs a Mongo-backed documents store.
func NewDocuments(logger mlogger.Logger, db *mongo.Database) (*Documents, error) {
if db == nil {
return nil, merrors.InvalidArgument("documentsStore: database is nil")
}
repo := repository.CreateMongoRepository(db, model.DocumentRecordsCollection)
indexes := []*ri.Definition{
{
Keys: []ri.Key{{Field: "paymentRef", Sort: ri.Asc}},
Unique: true,
},
}
for _, def := range indexes {
if err := repo.CreateIndex(def); err != nil {
logger.Error("failed to ensure documents index", zap.Error(err), zap.String("collection", repo.Collection()))
return nil, err
}
}
childLogger := logger.Named("documents")
childLogger.Debug("documents store initialised")
return &Documents{
logger: childLogger,
repo: repo,
}, nil
}
func (d *Documents) Create(ctx context.Context, record *model.DocumentRecord) error {
if record == nil {
return merrors.InvalidArgument("documentsStore: nil record")
}
record.Normalize()
if record.PaymentRef == "" {
return merrors.InvalidArgument("documentsStore: empty paymentRef")
}
record.Update()
if err := d.repo.Insert(ctx, record, repository.Filter("paymentRef", record.PaymentRef)); err != nil {
if errors.Is(err, merrors.ErrDataConflict) {
return storage.ErrDuplicateDocument
}
return err
}
d.logger.Debug("document record created", zap.String("payment_ref", record.PaymentRef))
return nil
}
func (d *Documents) Update(ctx context.Context, record *model.DocumentRecord) error {
if record == nil {
return merrors.InvalidArgument("documentsStore: nil record")
}
if record.ID.IsZero() {
return merrors.InvalidArgument("documentsStore: missing record id")
}
record.Normalize()
record.Update()
if err := d.repo.Update(ctx, record); err != nil {
if errors.Is(err, merrors.ErrNoData) {
return storage.ErrDocumentNotFound
}
return err
}
return nil
}
func (d *Documents) GetByPaymentRef(ctx context.Context, paymentRef string) (*model.DocumentRecord, error) {
paymentRef = strings.TrimSpace(paymentRef)
if paymentRef == "" {
return nil, merrors.InvalidArgument("documentsStore: empty paymentRef")
}
entity := &model.DocumentRecord{}
if err := d.repo.FindOneByFilter(ctx, repository.Filter("paymentRef", paymentRef), entity); err != nil {
if errors.Is(err, merrors.ErrNoData) {
return nil, storage.ErrDocumentNotFound
}
return nil, err
}
return entity, nil
}
func (d *Documents) ListByPaymentRefs(ctx context.Context, paymentRefs []string) ([]*model.DocumentRecord, error) {
refs := make([]string, 0, len(paymentRefs))
for _, ref := range paymentRefs {
clean := strings.TrimSpace(ref)
if clean == "" {
continue
}
refs = append(refs, clean)
}
if len(refs) == 0 {
return []*model.DocumentRecord{}, nil
}
query := repository.Query().Comparison(repository.Field("paymentRef"), builder.In, refs)
records := make([]*model.DocumentRecord, 0)
decoder := func(cur *mongo.Cursor) error {
var rec model.DocumentRecord
if err := cur.Decode(&rec); err != nil {
d.logger.Warn("failed to decode document record", zap.Error(err))
return err
}
records = append(records, &rec)
return nil
}
if err := d.repo.FindManyByFilter(ctx, query, decoder); err != nil {
return nil, err
}
return records, nil
}
var _ storage.DocumentsStore = (*Documents)(nil)

View File

@@ -0,0 +1,32 @@
package storage
import (
"context"
"github.com/tech/sendico/billing/documents/storage/model"
)
type storageError string
func (e storageError) Error() string {
return string(e)
}
var (
ErrDocumentNotFound = storageError("billing.documents.storage: document record not found")
ErrDuplicateDocument = storageError("billing.documents.storage: duplicate document record")
)
// Repository defines the root storage contract for the billing documents service.
type Repository interface {
Ping(ctx context.Context) error
Documents() DocumentsStore
}
// DocumentsStore exposes persistence operations for document records.
type DocumentsStore interface {
Create(ctx context.Context, record *model.DocumentRecord) error
Update(ctx context.Context, record *model.DocumentRecord) error
GetByPaymentRef(ctx context.Context, paymentRef string) (*model.DocumentRecord, error)
ListByPaymentRefs(ctx context.Context, paymentRefs []string) ([]*model.DocumentRecord, error)
}

View File

@@ -0,0 +1,67 @@
#spacer
#title
ACT OF ACCEPTANCE OF SERVICES
#subtitle
under the Public Offer Agreement
#meta
Date: {{ date .Date }}
Act No: {{ .PaymentID }}
#section
PARTIES
#text
This Act is made between the following Parties.
#kv
Executor | {{ .ExecutorFullName }}
Status | Individual
#section
BASIS
#text
This Act is issued pursuant to the Public Offer Agreement
accepted by the Executor by joining the offer.
#section
SERVICES RENDERED
#text
The Executor has rendered services to the Customer
in accordance with the terms of the Public Offer Agreement.
#section
REMUNERATION
#table
Description | Amount
Services rendered under the Public Offer Agreement | {{ money .Amount .Currency }}
#section
CONFIRMATION
#text
The Customer confirms that the services were rendered properly
and accepted without any claims.
The remuneration for the services was paid to the Executor
using the bank card details provided by the Executor.
#section
SIGNATURES
#sign
Customer ___________________________
Executor ___________________________

View File

@@ -0,0 +1,46 @@
root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"
[build]
args_bin = []
entrypoint = "./tmp/main"
cmd = "go build -o ./tmp/main ."
delay = 1000
exclude_dir = ["assets", "tmp", "vendor", "testdata"]
exclude_file = []
exclude_regex = ["_test.go", "_templ.go"]
exclude_unchanged = false
follow_symlink = false
full_bin = ""
include_dir = []
include_ext = ["go", "tpl", "tmpl", "html"]
include_file = []
kill_delay = "0s"
log = "build-errors.log"
poll = false
poll_interval = 0
post_cmd = []
pre_cmd = []
rerun = false
rerun_delay = 500
send_interrupt = false
stop_on_error = false
[color]
app = ""
build = "yellow"
main = "magenta"
runner = "green"
watcher = "cyan"
[log]
main_only = false
time = false
[misc]
clean_on_exit = false
[screen]
clear_on_rebuild = false
keep_scroll = true

3
api/billing/fees/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
internal/generated
.gocache
/app

View File

@@ -0,0 +1,42 @@
runtime:
shutdown_timeout_seconds: 15
grpc:
network: tcp
address: ":50060"
advertise_host: "dev-billing-fees"
enable_reflection: true
enable_health: true
metrics:
address: ":9402"
database:
driver: mongodb
settings:
host_env: FEES_MONGO_HOST
port_env: FEES_MONGO_PORT
database_env: FEES_MONGO_DATABASE
user_env: FEES_MONGO_USER
password_env: FEES_MONGO_PASSWORD
auth_source_env: FEES_MONGO_AUTH_SOURCE
replica_set_env: FEES_MONGO_REPLICA_SET
messaging:
driver: NATS
settings:
url_env: NATS_URL
host_env: NATS_HOST
port_env: NATS_PORT
username_env: NATS_USER
password_env: NATS_PASSWORD
broker_name: Billing Fees Service
max_reconnects: 10
reconnect_wait: 5
buffer_size: 1024
oracle:
address: "dev-fx-oracle:50051"
dial_timeout_seconds: 5
call_timeout_seconds: 3
insecure: true

View File

@@ -0,0 +1,42 @@
runtime:
shutdown_timeout_seconds: 15
grpc:
network: tcp
address: ":50060"
advertise_host: "sendico_billing_fees"
enable_reflection: true
enable_health: true
metrics:
address: ":9402"
database:
driver: mongodb
settings:
host_env: FEES_MONGO_HOST
port_env: FEES_MONGO_PORT
database_env: FEES_MONGO_DATABASE
user_env: FEES_MONGO_USER
password_env: FEES_MONGO_PASSWORD
auth_source_env: FEES_MONGO_AUTH_SOURCE
replica_set_env: FEES_MONGO_REPLICA_SET
messaging:
driver: NATS
settings:
url_env: NATS_URL
host_env: NATS_HOST
port_env: NATS_PORT
username_env: NATS_USER
password_env: NATS_PASSWORD
broker_name: Billing Fees Service
max_reconnects: 10
reconnect_wait: 5
buffer_size: 1024
oracle:
address: "sendico_fx_oracle:50051"
dial_timeout_seconds: 5
call_timeout_seconds: 3
insecure: true

1
api/billing/fees/env/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.env.api

55
api/billing/fees/go.mod Normal file
View File

@@ -0,0 +1,55 @@
module github.com/tech/sendico/billing/fees
go 1.25.6
replace github.com/tech/sendico/pkg => ../../pkg
replace github.com/tech/sendico/fx/oracle => ../../fx/oracle
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.78.0
gopkg.in/yaml.v3 v3.0.1
)
require (
github.com/casbin/mongodb-adapter/v4 v4.3.0 // indirect
go.mongodb.org/mongo-driver/v2 v2.5.0
)
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/bmatcuk/doublestar/v4 v4.10.0 // indirect
github.com/casbin/casbin/v2 v2.135.0 // indirect
github.com/casbin/govaluate v1.10.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/go-chi/chi/v5 v5.2.4 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/klauspost/compress v1.18.3 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nats-io/nats.go v1.48.0 // indirect
github.com/nats-io/nkeys v0.4.15 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
github.com/prometheus/client_golang v1.23.2
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.67.5 // indirect
github.com/prometheus/procfs v0.19.2 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.2.0 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
golang.org/x/crypto v0.47.0 // indirect
golang.org/x/net v0.49.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.40.0 // indirect
golang.org/x/text v0.33.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260202165425-ce8ad4cf556b // indirect
google.golang.org/protobuf v1.36.11
)

221
api/billing/fees/go.sum Normal file
View File

@@ -0,0 +1,221 @@
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs=
github.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/casbin/casbin/v2 v2.135.0 h1:6BLkMQiGotYyS5yYeWgW19vxqugUlvHFkFiLnLR/bxk=
github.com/casbin/casbin/v2 v2.135.0/go.mod h1:FmcfntdXLTcYXv/hxgNntcRPqAbwOG9xsism0yXT+18=
github.com/casbin/govaluate v1.3.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A=
github.com/casbin/govaluate v1.10.0 h1:ffGw51/hYH3w3rZcxO/KcaUIDOLP84w7nsidMVgaDG0=
github.com/casbin/govaluate v1.10.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A=
github.com/casbin/mongodb-adapter/v4 v4.3.0 h1:yYXky9v1by6vj/0QK7OyHyd/xpz4vzh0lCi7JKrS4qQ=
github.com/casbin/mongodb-adapter/v4 v4.3.0/go.mod h1:bOTSYZUjX7I9E0ExEvgq46m3mcDNRII7g8iWjrM1BHE=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA=
github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI=
github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4=
github.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw=
github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 h1:mFWunSatvkQQDhpdyuFAYwyAan3hzCuma+Pz8sqvOfg=
github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo=
github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/nats-io/nats.go v1.48.0 h1:pSFyXApG+yWU/TgbKCjmm5K4wrHu86231/w84qRVR+U=
github.com/nats-io/nats.go v1.48.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
github.com/nats-io/nkeys v0.4.15 h1:JACV5jRVO9V856KOapQ7x+EY8Jo3qw1vJt/9Jpwzkk4=
github.com/nats-io/nkeys v0.4.15/go.mod h1:CpMchTXC9fxA5zrMo4KpySxNjiDVvr8ANOSZdiNfUrs=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/testcontainers/testcontainers-go v0.33.0 h1:zJS9PfXYT5O0ZFXM2xxXfk4J5UMw/kRiISng037Gxdw=
github.com/testcontainers/testcontainers-go v0.33.0/go.mod h1:W80YpTa8D5C3Yy16icheD01UTDu+LmXIA2Keo+jWtT8=
github.com/testcontainers/testcontainers-go/modules/mongodb v0.33.0 h1:iXVA84s5hKMS5gn01GWOYHE3ymy/2b+0YkpFeTxB2XY=
github.com/testcontainers/testcontainers-go/modules/mongodb v0.33.0/go.mod h1:R6tMjTojRiaoo89fh/hf7tOmfzohdqSU17R9DwSVSog=
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.2.0 h1:bYKF2AEwG5rqd1BumT4gAnvwU/M9nBp2pTSxeZw7Wvs=
github.com/xdg-go/scram v1.2.0/go.mod h1:3dlrS0iBaWKYVt2ZfA4cj48umJZ+cAEbR6/SjLA88I8=
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF3xaE=
go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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-20260202165425-ce8ad4cf556b h1:GZxXGdFaHX27ZSMHudWc4FokdD+xl8BC2UJm1OVIEzs=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260202165425-ce8ad4cf556b/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
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=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -0,0 +1,28 @@
package appversion
import (
"github.com/tech/sendico/pkg/version"
vf "github.com/tech/sendico/pkg/version/factory"
)
// Build information populated at build time.
var (
Version string
Revision string
Branch string
BuildUser string
BuildDate string
)
// Create initialises a version.Printer with the build details for this service.
func Create() version.Printer {
info := version.Info{
Program: "Sendico Billing Fees Service",
Revision: Revision,
Branch: Branch,
BuildUser: BuildUser,
BuildDate: BuildDate,
Version: Version,
}
return vf.Create(&info)
}

View File

@@ -0,0 +1,178 @@
package serverimp
import (
"context"
"os"
"strings"
"time"
"github.com/tech/sendico/billing/fees/internal/service/fees"
"github.com/tech/sendico/billing/fees/storage"
mongostorage "github.com/tech/sendico/billing/fees/storage/mongo"
oracleclient "github.com/tech/sendico/fx/oracle/client"
"github.com/tech/sendico/pkg/api/routers"
"github.com/tech/sendico/pkg/db"
msg "github.com/tech/sendico/pkg/messaging"
"github.com/tech/sendico/pkg/mlogger"
"github.com/tech/sendico/pkg/server/grpcapp"
"go.uber.org/zap"
"gopkg.in/yaml.v3"
)
type Imp struct {
logger mlogger.Logger
file string
debug bool
config *config
app *grpcapp.App[storage.Repository]
oracleClient oracleclient.Client
service *fees.Service
}
type config struct {
*grpcapp.Config `yaml:",inline"`
Oracle OracleConfig `yaml:"oracle"`
}
type OracleConfig struct {
Address string `yaml:"address"`
DialTimeoutSecs int `yaml:"dial_timeout_seconds"`
CallTimeoutSecs int `yaml:"call_timeout_seconds"`
InsecureTransport bool `yaml:"insecure"`
}
func (c OracleConfig) dialTimeout() time.Duration {
if c.DialTimeoutSecs <= 0 {
return 5 * time.Second
}
return time.Duration(c.DialTimeoutSecs) * time.Second
}
func (c OracleConfig) callTimeout() time.Duration {
if c.CallTimeoutSecs <= 0 {
return 3 * time.Second
}
return time.Duration(c.CallTimeoutSecs) * time.Second
}
// Create initialises the billing fees server implementation.
func Create(logger mlogger.Logger, file string, debug bool) (*Imp, error) {
return &Imp{
logger: logger.Named("server"),
file: file,
debug: debug,
}, nil
}
func (i *Imp) Shutdown() {
if i.app == nil {
if i.service != nil {
i.service.Shutdown()
}
if i.oracleClient != nil {
_ = i.oracleClient.Close()
}
return
}
timeout := 15 * time.Second
if i.config != nil && i.config.Runtime != nil {
timeout = i.config.Runtime.ShutdownTimeout()
}
if i.service != nil {
i.service.Shutdown()
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
i.app.Shutdown(ctx)
cancel()
if i.oracleClient != nil {
_ = i.oracleClient.Close()
}
}
func (i *Imp) Start() error {
cfg, err := i.loadConfig()
if err != nil {
return err
}
i.config = cfg
repoFactory := func(logger mlogger.Logger, conn *db.MongoConnection) (storage.Repository, error) {
return mongostorage.New(logger, conn)
}
var oracleClient oracleclient.Client
if addr := strings.TrimSpace(cfg.Oracle.Address); addr != "" {
dialCtx, cancel := context.WithTimeout(context.Background(), cfg.Oracle.dialTimeout())
defer cancel()
oc, err := oracleclient.New(dialCtx, oracleclient.Config{
Address: addr,
DialTimeout: cfg.Oracle.dialTimeout(),
CallTimeout: cfg.Oracle.callTimeout(),
Insecure: cfg.Oracle.InsecureTransport,
})
if err != nil {
i.logger.Warn("failed to initialise oracle client", zap.String("address", addr), zap.Error(err))
} else {
oracleClient = oc
i.oracleClient = oc
i.logger.Info("connected to oracle service", zap.String("address", addr))
}
}
serviceFactory := func(logger mlogger.Logger, repo storage.Repository, producer msg.Producer) (grpcapp.Service, error) {
opts := []fees.Option{}
if oracleClient != nil {
opts = append(opts, fees.WithOracleClient(oracleClient))
}
if cfg.GRPC != nil {
if invokeURI := cfg.GRPC.DiscoveryInvokeURI(); invokeURI != "" {
opts = append(opts, fees.WithDiscoveryInvokeURI(invokeURI))
}
}
svc := fees.NewService(logger, repo, producer, opts...)
i.service = svc
return svc, nil
}
app, err := grpcapp.NewApp(i.logger, "billing_fees", cfg.Config, i.debug, repoFactory, serviceFactory)
if err != nil {
return err
}
i.app = app
return i.app.Start()
}
func (i *Imp) loadConfig() (*config, error) {
data, err := os.ReadFile(i.file)
if err != nil {
i.logger.Error("Could not read configuration file", zap.String("config_file", i.file), zap.Error(err))
return nil, err
}
cfg := &config{Config: &grpcapp.Config{}}
if err := yaml.Unmarshal(data, cfg); err != nil {
i.logger.Error("Failed to parse configuration", zap.Error(err))
return nil, err
}
if cfg.Runtime == nil {
cfg.Runtime = &grpcapp.RuntimeConfig{ShutdownTimeoutSeconds: 15}
}
if cfg.GRPC == nil {
cfg.GRPC = &routers.GRPCConfig{
Network: "tcp",
Address: ":50060",
EnableReflection: true,
EnableHealth: true,
}
}
return cfg, nil
}

View File

@@ -0,0 +1,12 @@
package server
import (
serverimp "github.com/tech/sendico/billing/fees/internal/server/internal"
"github.com/tech/sendico/pkg/mlogger"
"github.com/tech/sendico/pkg/server"
)
// Create constructs the billing fees server implementation.
func Create(logger mlogger.Logger, file string, debug bool) (server.Application, error) {
return serverimp.Create(logger, file, debug)
}

View File

@@ -0,0 +1,17 @@
package fees
import (
"context"
"time"
"github.com/tech/sendico/billing/fees/internal/service/fees/types"
"github.com/tech/sendico/billing/fees/storage/model"
feesv1 "github.com/tech/sendico/pkg/proto/billing/fees/v1"
tracev1 "github.com/tech/sendico/pkg/proto/common/trace/v1"
)
// Calculator isolates fee rule evaluation logic so it can be reused and tested.
// Implementation lives under internal/service/fees/internal/calculator.
type Calculator interface {
Compute(ctx context.Context, plan *model.FeePlan, intent *feesv1.Intent, bookedAt time.Time, trace *tracev1.TraceContext) (*types.CalculationResult, error)
}

View File

@@ -0,0 +1,462 @@
package calculator
import (
"context"
"errors"
"math/big"
"sort"
"strconv"
"strings"
"time"
"github.com/tech/sendico/billing/fees/internal/service/fees/types"
"github.com/tech/sendico/billing/fees/storage/model"
oracleclient "github.com/tech/sendico/fx/oracle/client"
dmath "github.com/tech/sendico/pkg/decimal"
"github.com/tech/sendico/pkg/merrors"
"github.com/tech/sendico/pkg/mlogger"
feesv1 "github.com/tech/sendico/pkg/proto/billing/fees/v1"
accountingv1 "github.com/tech/sendico/pkg/proto/common/accounting/v1"
fxv1 "github.com/tech/sendico/pkg/proto/common/fx/v1"
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
tracev1 "github.com/tech/sendico/pkg/proto/common/trace/v1"
"go.uber.org/zap"
)
// fxOracle captures the oracle dependency for FX conversions.
type fxOracle interface {
LatestRate(ctx context.Context, req oracleclient.LatestRateParams) (*oracleclient.RateSnapshot, error)
}
// New constructs the default calculator implementation.
func New(logger mlogger.Logger, oracle fxOracle) *quoteCalculator {
if logger == nil {
logger = zap.NewNop()
}
return &quoteCalculator{
logger: logger.Named("calculator"),
oracle: oracle,
}
}
type quoteCalculator struct {
logger mlogger.Logger
oracle fxOracle
}
func (c *quoteCalculator) Compute(ctx context.Context, plan *model.FeePlan, intent *feesv1.Intent, bookedAt time.Time, _ *tracev1.TraceContext) (*types.CalculationResult, error) {
if plan == nil {
return nil, merrors.InvalidArgument("plan is required")
}
if intent == nil {
return nil, merrors.InvalidArgument("intent is required")
}
trigger := convertTrigger(intent.GetTrigger())
if trigger == model.TriggerUnspecified {
return nil, merrors.InvalidArgument("unsupported trigger")
}
baseAmount, err := dmath.RatFromString(intent.GetBaseAmount().GetAmount())
if err != nil {
return nil, merrors.InvalidArgument("invalid base amount")
}
if baseAmount.Sign() < 0 {
return nil, merrors.InvalidArgument("base amount cannot be negative")
}
baseScale := inferScale(intent.GetBaseAmount().GetAmount())
rules := make([]model.FeeRule, len(plan.Rules))
copy(rules, plan.Rules)
sort.SliceStable(rules, func(i, j int) bool {
if rules[i].Priority == rules[j].Priority {
return rules[i].RuleID < rules[j].RuleID
}
return rules[i].Priority < rules[j].Priority
})
lines := make([]*feesv1.DerivedPostingLine, 0, len(rules))
applied := make([]*feesv1.AppliedRule, 0, len(rules))
planID := ""
if planRef := plan.GetID(); planRef != nil && !planRef.IsZero() {
planID = planRef.Hex()
}
for _, rule := range rules {
if !shouldApplyRule(rule, trigger, intent.GetAttributes(), bookedAt) {
continue
}
ledgerAccountRef := strings.TrimSpace(rule.LedgerAccountRef)
amount, scale, calcErr := c.calculateRuleAmount(baseAmount, baseScale, rule)
if calcErr != nil {
if !errors.Is(calcErr, merrors.ErrInvalidArg) {
c.logger.Warn("failed to calculate fee rule amount", zap.String("rule_id", rule.RuleID), zap.Error(calcErr))
}
continue
}
if amount.Sign() == 0 {
continue
}
currency := intent.GetBaseAmount().GetCurrency()
if override := strings.TrimSpace(rule.Currency); override != "" {
currency = override
}
entrySide := mapEntrySide(rule.EntrySide)
if entrySide == accountingv1.EntrySide_ENTRY_SIDE_UNSPECIFIED {
// Default fees to debit (i.e. charge the customer) when entry side is not specified.
entrySide = accountingv1.EntrySide_ENTRY_SIDE_DEBIT
}
meta := map[string]string{
"fee_rule_id": rule.RuleID,
}
if planID != "" {
meta["fee_plan_id"] = planID
}
if rule.Metadata != nil {
if taxCode := strings.TrimSpace(rule.Metadata["tax_code"]); taxCode != "" {
meta["tax_code"] = taxCode
}
if taxRate := strings.TrimSpace(rule.Metadata["tax_rate"]); taxRate != "" {
meta["tax_rate"] = taxRate
}
}
lines = append(lines, &feesv1.DerivedPostingLine{
LedgerAccountRef: ledgerAccountRef,
Money: &moneyv1.Money{
Amount: dmath.FormatRat(amount, scale),
Currency: currency,
},
LineType: mapLineType(rule.LineType),
Side: entrySide,
Meta: meta,
})
applied = append(applied, &feesv1.AppliedRule{
RuleId: rule.RuleID,
RuleVersion: planID,
Formula: rule.Formula,
Rounding: mapRoundingMode(rule.Rounding),
TaxCode: metadataValue(rule.Metadata, "tax_code"),
TaxRate: metadataValue(rule.Metadata, "tax_rate"),
Parameters: cloneStringMap(rule.Metadata),
})
}
var fxUsed *feesv1.FXUsed
if trigger == model.TriggerFXConversion && c.oracle != nil {
fxUsed = c.buildFxUsed(ctx, intent)
}
return &types.CalculationResult{
Lines: lines,
Applied: applied,
FxUsed: fxUsed,
}, nil
}
func (c *quoteCalculator) calculateRuleAmount(baseAmount *big.Rat, baseScale uint32, rule model.FeeRule) (*big.Rat, uint32, error) {
scale, err := resolveRuleScale(rule, baseScale)
if err != nil {
return nil, 0, err
}
result := new(big.Rat)
if percentage := strings.TrimSpace(rule.Percentage); percentage != "" {
percentageRat, perr := dmath.RatFromString(percentage)
if perr != nil {
return nil, 0, merrors.InvalidArgument("invalid percentage")
}
result = dmath.AddRat(result, dmath.MulRat(baseAmount, percentageRat))
}
if fixed := strings.TrimSpace(rule.FixedAmount); fixed != "" {
fixedRat, ferr := dmath.RatFromString(fixed)
if ferr != nil {
return nil, 0, merrors.InvalidArgument("invalid fixed amount")
}
result = dmath.AddRat(result, fixedRat)
}
if minStr := strings.TrimSpace(rule.MinimumAmount); minStr != "" {
minRat, merr := dmath.RatFromString(minStr)
if merr != nil {
return nil, 0, merrors.InvalidArgument("invalid minimum amount")
}
if dmath.CmpRat(result, minRat) < 0 {
result = new(big.Rat).Set(minRat)
}
}
if maxStr := strings.TrimSpace(rule.MaximumAmount); maxStr != "" {
maxRat, merr := dmath.RatFromString(maxStr)
if merr != nil {
return nil, 0, merrors.InvalidArgument("invalid maximum amount")
}
if dmath.CmpRat(result, maxRat) > 0 {
result = new(big.Rat).Set(maxRat)
}
}
if result.Sign() < 0 {
result = new(big.Rat).Abs(result)
}
rounded, rerr := dmath.RoundRatToScale(result, scale, toDecimalRounding(rule.Rounding))
if rerr != nil {
return nil, 0, rerr
}
return rounded, scale, nil
}
const (
attrFxBaseCurrency = "fx_base_currency"
attrFxQuoteCurrency = "fx_quote_currency"
attrFxProvider = "fx_provider"
attrFxSide = "fx_side"
attrFxRateOverride = "fx_rate"
)
func (c *quoteCalculator) buildFxUsed(ctx context.Context, intent *feesv1.Intent) *feesv1.FXUsed {
if intent == nil || c.oracle == nil {
return nil
}
attrs := intent.GetAttributes()
base := strings.TrimSpace(attrs[attrFxBaseCurrency])
quote := strings.TrimSpace(attrs[attrFxQuoteCurrency])
if base == "" || quote == "" {
return nil
}
pair := &fxv1.CurrencyPair{Base: base, Quote: quote}
provider := strings.TrimSpace(attrs[attrFxProvider])
snapshot, err := c.oracle.LatestRate(ctx, oracleclient.LatestRateParams{
Meta: oracleclient.RequestMeta{},
Pair: pair,
Provider: provider,
})
if err != nil {
c.logger.Warn("fees: failed to fetch FX context", zap.Error(err))
return nil
}
if snapshot == nil {
return nil
}
rateValue := strings.TrimSpace(attrs[attrFxRateOverride])
if rateValue == "" {
rateValue = snapshot.Mid
}
if rateValue == "" {
rateValue = snapshot.Ask
}
if rateValue == "" {
rateValue = snapshot.Bid
}
return &feesv1.FXUsed{
Pair: pair,
Side: parseFxSide(strings.TrimSpace(attrs[attrFxSide])),
Rate: &moneyv1.Decimal{Value: rateValue},
AsofUnixMs: snapshot.AsOf.UnixMilli(),
Provider: snapshot.Provider,
RateRef: snapshot.RateRef,
SpreadBps: &moneyv1.Decimal{Value: snapshot.SpreadBps},
}
}
func parseFxSide(value string) fxv1.Side {
switch strings.ToLower(value) {
case "buy_base", "buy_base_sell_quote", "buy":
return fxv1.Side_BUY_BASE_SELL_QUOTE
case "sell_base", "sell_base_buy_quote", "sell":
return fxv1.Side_SELL_BASE_BUY_QUOTE
default:
return fxv1.Side_SIDE_UNSPECIFIED
}
}
func inferScale(amount string) uint32 {
value := strings.TrimSpace(amount)
if value == "" {
return 0
}
if idx := strings.IndexAny(value, "eE"); idx >= 0 {
value = value[:idx]
}
if strings.HasPrefix(value, "+") || strings.HasPrefix(value, "-") {
value = value[1:]
}
if dot := strings.IndexByte(value, '.'); dot >= 0 {
return uint32(len(value[dot+1:]))
}
return 0
}
func shouldApplyRule(rule model.FeeRule, trigger model.Trigger, attributes map[string]string, bookedAt time.Time) bool {
if rule.Trigger != trigger {
return false
}
if rule.EffectiveFrom.After(bookedAt) {
return false
}
if rule.EffectiveTo != nil && rule.EffectiveTo.Before(bookedAt) {
return false
}
return ruleMatchesAttributes(rule, attributes)
}
func resolveRuleScale(rule model.FeeRule, fallback uint32) (uint32, error) {
if rule.Metadata != nil {
for _, field := range []string{"scale", "decimals", "precision"} {
if value, ok := rule.Metadata[field]; ok && strings.TrimSpace(value) != "" {
return parseScale(field, value)
}
}
}
return fallback, nil
}
func parseScale(field, value string) (uint32, error) {
clean := strings.TrimSpace(value)
if clean == "" {
return 0, merrors.InvalidArgument(field + " is empty")
}
parsed, err := strconv.ParseUint(clean, 10, 32)
if err != nil {
return 0, merrors.InvalidArgument("invalid " + field + " value")
}
return uint32(parsed), nil
}
func metadataValue(meta map[string]string, key string) string {
if meta == nil {
return ""
}
return strings.TrimSpace(meta[key])
}
func cloneStringMap(src map[string]string) map[string]string {
if len(src) == 0 {
return nil
}
cloned := make(map[string]string, len(src))
for k, v := range src {
cloned[k] = v
}
return cloned
}
func ruleMatchesAttributes(rule model.FeeRule, attributes map[string]string) bool {
if len(rule.AppliesTo) == 0 {
return true
}
for key, value := range rule.AppliesTo {
if attributes == nil {
return false
}
attrValue, ok := attributes[key]
if !ok {
return false
}
if !matchesAttributeValue(value, attrValue) {
return false
}
}
return true
}
func matchesAttributeValue(expected, actual string) bool {
trimmed := strings.TrimSpace(expected)
if trimmed == "" {
return actual == ""
}
values := strings.Split(trimmed, ",")
for _, value := range values {
value = strings.TrimSpace(value)
if value == "" {
continue
}
if value == "*" || value == actual {
return true
}
}
return false
}
func mapLineType(lineType string) accountingv1.PostingLineType {
switch strings.ToLower(lineType) {
case "tax":
return accountingv1.PostingLineType_POSTING_LINE_TAX
case "spread":
return accountingv1.PostingLineType_POSTING_LINE_SPREAD
case "reversal":
return accountingv1.PostingLineType_POSTING_LINE_REVERSAL
default:
return accountingv1.PostingLineType_POSTING_LINE_FEE
}
}
func mapEntrySide(entrySide string) accountingv1.EntrySide {
switch strings.ToLower(entrySide) {
case "debit":
return accountingv1.EntrySide_ENTRY_SIDE_DEBIT
case "credit":
return accountingv1.EntrySide_ENTRY_SIDE_CREDIT
default:
return accountingv1.EntrySide_ENTRY_SIDE_UNSPECIFIED
}
}
func toDecimalRounding(mode string) dmath.RoundingMode {
switch strings.ToLower(strings.TrimSpace(mode)) {
case "half_up":
return dmath.RoundingModeHalfUp
case "down":
return dmath.RoundingModeDown
case "half_even", "bankers":
return dmath.RoundingModeHalfEven
default:
return dmath.RoundingModeHalfEven
}
}
func mapRoundingMode(mode string) moneyv1.RoundingMode {
switch strings.ToLower(mode) {
case "half_up":
return moneyv1.RoundingMode_ROUND_HALF_UP
case "down":
return moneyv1.RoundingMode_ROUND_DOWN
default:
return moneyv1.RoundingMode_ROUND_HALF_EVEN
}
}
func convertTrigger(trigger feesv1.Trigger) model.Trigger {
switch trigger {
case feesv1.Trigger_TRIGGER_CAPTURE:
return model.TriggerCapture
case feesv1.Trigger_TRIGGER_REFUND:
return model.TriggerRefund
case feesv1.Trigger_TRIGGER_DISPUTE:
return model.TriggerDispute
case feesv1.Trigger_TRIGGER_PAYOUT:
return model.TriggerPayout
case feesv1.Trigger_TRIGGER_FX_CONVERSION:
return model.TriggerFXConversion
default:
return model.TriggerUnspecified
}
}

View File

@@ -0,0 +1,10 @@
package resolver
import "github.com/tech/sendico/pkg/merrors"
var (
// ErrNoFeeRuleFound indicates that no applicable rule exists for the given context.
ErrNoFeeRuleFound = merrors.ErrNoData
// ErrConflictingFeeRules indicates multiple rules share the same highest priority.
ErrConflictingFeeRules = merrors.ErrDataConflict
)

View File

@@ -0,0 +1,235 @@
package resolver
import (
"context"
"errors"
"strings"
"time"
"github.com/tech/sendico/billing/fees/storage"
"github.com/tech/sendico/billing/fees/storage/model"
"github.com/tech/sendico/pkg/merrors"
"github.com/tech/sendico/pkg/mutil/mzap"
"go.mongodb.org/mongo-driver/v2/bson"
"go.uber.org/zap"
)
type planFinder interface {
FindActiveOrgPlan(ctx context.Context, orgRef bson.ObjectID, at time.Time) (*model.FeePlan, error)
FindActiveGlobalPlan(ctx context.Context, at time.Time) (*model.FeePlan, error)
}
type feeResolver struct {
plans storage.PlansStore
finder planFinder
logger *zap.Logger
}
func New(plans storage.PlansStore, logger *zap.Logger) *feeResolver {
var finder planFinder
if pf, ok := plans.(planFinder); ok {
finder = pf
}
if logger == nil {
logger = zap.NewNop()
}
return &feeResolver{
plans: plans,
finder: finder,
logger: logger.Named("resolver"),
}
}
func (r *feeResolver) ResolveFeeRule(ctx context.Context, orgRef *bson.ObjectID, trigger model.Trigger, at time.Time, attrs map[string]string) (*model.FeePlan, *model.FeeRule, error) {
if r.plans == nil {
return nil, nil, merrors.InvalidArgument("fees: plans store is required")
}
// Try org-specific first if provided.
if orgRef != nil && !orgRef.IsZero() {
if plan, err := r.getOrgPlan(ctx, *orgRef, at); err == nil {
if rule, selErr := selectRule(plan, trigger, at, attrs); selErr == nil {
return plan, rule, nil
} else if !errors.Is(selErr, ErrNoFeeRuleFound) {
r.logger.Warn("Failed selecting rule for org plan", zap.Error(selErr), mzap.ObjRef("org_ref", *orgRef))
return nil, nil, selErr
}
orgFields := []zap.Field{
mzap.ObjRef("org_ref", *orgRef),
zap.String("trigger", string(trigger)),
zap.Time("booked_at", at),
zap.Any("attributes", attrs),
}
orgFields = append(orgFields, zapFieldsForPlan(plan)...)
r.logger.Debug("No matching rule in org plan; falling back to global", orgFields...)
} else if !errors.Is(err, storage.ErrFeePlanNotFound) {
r.logger.Warn("Failed resolving org fee plan", zap.Error(err), mzap.ObjRef("org_ref", *orgRef))
return nil, nil, err
}
}
plan, err := r.getGlobalPlan(ctx, at)
if err != nil {
if errors.Is(err, storage.ErrFeePlanNotFound) {
r.logger.Debug("No applicable global fee plan found", zap.String("trigger", string(trigger)),
zap.Time("booked_at", at), zap.Any("attributes", attrs),
)
return nil, nil, merrors.NoData("fees: no applicable fee rule found")
}
r.logger.Warn("Failed resolving global fee plan", zap.Error(err))
return nil, nil, err
}
rule, err := selectRule(plan, trigger, at, attrs)
if err != nil {
if !errors.Is(err, ErrNoFeeRuleFound) {
r.logger.Warn("Failed selecting rule in global plan", zap.Error(err))
} else {
globalFields := []zap.Field{
zap.String("trigger", string(trigger)),
zap.Time("booked_at", at),
zap.Any("attributes", attrs),
}
globalFields = append(globalFields, zapFieldsForPlan(plan)...)
r.logger.Debug("No matching rule in global plan", globalFields...)
}
return nil, nil, err
}
selectedFields := []zap.Field{
zap.String("trigger", string(trigger)),
zap.Time("booked_at", at),
zap.Any("attributes", attrs),
zap.String("rule_id", rule.RuleID),
zap.Int("rule_priority", rule.Priority),
zap.Any("rule_applies_to", rule.AppliesTo),
zap.Time("rule_effective_from", rule.EffectiveFrom),
}
if rule.EffectiveTo != nil {
selectedFields = append(selectedFields, zap.Time("rule_effective_to", *rule.EffectiveTo))
}
if orgRef != nil && !orgRef.IsZero() {
selectedFields = append(selectedFields, mzap.ObjRef("org_ref", *orgRef))
}
selectedFields = append(selectedFields, zapFieldsForPlan(plan)...)
r.logger.Debug("Selected fee rule", selectedFields...)
return plan, rule, nil
}
func (r *feeResolver) getOrgPlan(ctx context.Context, orgRef bson.ObjectID, at time.Time) (*model.FeePlan, error) {
if r.finder != nil {
return r.finder.FindActiveOrgPlan(ctx, orgRef, at)
}
return r.plans.GetActivePlan(ctx, orgRef, at)
}
func (r *feeResolver) getGlobalPlan(ctx context.Context, at time.Time) (*model.FeePlan, error) {
if r.finder != nil {
return r.finder.FindActiveGlobalPlan(ctx, at)
}
// Treat zero ObjectID as global in legacy path.
return r.plans.GetActivePlan(ctx, bson.NilObjectID, at)
}
func selectRule(plan *model.FeePlan, trigger model.Trigger, at time.Time, attrs map[string]string) (*model.FeeRule, error) {
if plan == nil {
return nil, merrors.NoData("fees: no applicable fee rule found")
}
var selected *model.FeeRule
var highestPriority int
for _, rule := range plan.Rules {
if rule.Trigger != trigger {
continue
}
if rule.EffectiveFrom.After(at) {
continue
}
if rule.EffectiveTo != nil && !rule.EffectiveTo.After(at) {
continue
}
if !matchesAppliesTo(rule.AppliesTo, attrs) {
continue
}
if selected == nil || rule.Priority > highestPriority {
copy := rule
selected = &copy
highestPriority = rule.Priority
continue
}
if rule.Priority == highestPriority {
return nil, merrors.DataConflict("fees: conflicting fee rules")
}
}
if selected == nil {
return nil, merrors.NoData("fees: no applicable fee rule found")
}
return selected, nil
}
func matchesAppliesTo(appliesTo map[string]string, attrs map[string]string) bool {
if len(appliesTo) == 0 {
return true
}
for key, value := range appliesTo {
if attrs == nil {
return false
}
attrValue, ok := attrs[key]
if !ok {
return false
}
if !matchesAppliesValue(value, attrValue) {
return false
}
}
return true
}
func matchesAppliesValue(expected, actual string) bool {
trimmed := strings.TrimSpace(expected)
if trimmed == "" {
return actual == ""
}
values := strings.Split(trimmed, ",")
for _, value := range values {
value = strings.TrimSpace(value)
if value == "" {
continue
}
if value == "*" || value == actual {
return true
}
}
return false
}
func zapFieldsForPlan(plan *model.FeePlan) []zap.Field {
if plan == nil {
return []zap.Field{zap.Bool("plan_present", false)}
}
fields := []zap.Field{
zap.Bool("plan_present", true),
zap.Bool("plan_active", plan.Active),
zap.Time("plan_effective_from", plan.EffectiveFrom),
zap.Int("plan_rules_count", len(plan.Rules)),
}
if plan.EffectiveTo != nil {
fields = append(fields, zap.Time("plan_effective_to", *plan.EffectiveTo))
} else {
fields = append(fields, zap.Bool("plan_effective_to_set", false))
}
if plan.OrganizationRef != nil && !plan.OrganizationRef.IsZero() {
fields = append(fields, mzap.ObjRef("plan_org_ref", *plan.OrganizationRef))
} else {
fields = append(fields, zap.Bool("plan_org_ref_set", false))
}
if plan.GetID() != nil && !plan.GetID().IsZero() {
fields = append(fields, mzap.StorableRef(plan))
}
return fields
}

View File

@@ -0,0 +1,355 @@
package resolver
import (
"context"
"errors"
"testing"
"time"
"github.com/tech/sendico/billing/fees/storage"
"github.com/tech/sendico/billing/fees/storage/model"
"go.mongodb.org/mongo-driver/v2/bson"
"go.uber.org/zap"
)
func TestResolver_GlobalFallbackWhenOrgMissing(t *testing.T) {
t.Helper()
now := time.Now()
globalPlan := &model.FeePlan{
Active: true,
EffectiveFrom: now.Add(-time.Hour),
Rules: []model.FeeRule{
{RuleID: "global_capture", Trigger: model.TriggerCapture, Priority: 5, Percentage: "0.05", EffectiveFrom: now.Add(-time.Hour)},
},
}
store := &memoryPlansStore{plans: []*model.FeePlan{globalPlan}}
resolver := New(store, zap.NewNop())
orgA := bson.NewObjectID()
plan, rule, err := resolver.ResolveFeeRule(context.Background(), &orgA, model.TriggerCapture, now, nil)
if err != nil {
t.Fatalf("expected fallback to global, got error: %v", err)
}
if plan.OrganizationRef != nil && !plan.OrganizationRef.IsZero() {
t.Fatalf("expected global plan, got orgRef %s", plan.OrganizationRef.Hex())
}
if rule.RuleID != "global_capture" {
t.Fatalf("unexpected rule selected: %s", rule.RuleID)
}
}
func TestResolver_OrgOverridesGlobal(t *testing.T) {
t.Helper()
now := time.Now()
org := bson.NewObjectID()
globalPlan := &model.FeePlan{
Active: true,
EffectiveFrom: now.Add(-time.Hour),
Rules: []model.FeeRule{
{RuleID: "global_capture", Trigger: model.TriggerCapture, Priority: 5, Percentage: "0.05", EffectiveFrom: now.Add(-time.Hour)},
},
}
orgPlan := &model.FeePlan{
Active: true,
EffectiveFrom: now.Add(-time.Hour),
Rules: []model.FeeRule{
{RuleID: "org_capture", Trigger: model.TriggerCapture, Priority: 10, Percentage: "0.03", EffectiveFrom: now.Add(-time.Hour)},
},
}
orgPlan.OrganizationRef = &org
store := &memoryPlansStore{plans: []*model.FeePlan{globalPlan, orgPlan}}
resolver := New(store, zap.NewNop())
_, rule, err := resolver.ResolveFeeRule(context.Background(), &org, model.TriggerCapture, now, nil)
if err != nil {
t.Fatalf("expected org plan rule, got error: %v", err)
}
if rule.RuleID != "org_capture" {
t.Fatalf("expected org rule, got %s", rule.RuleID)
}
otherOrg := bson.NewObjectID()
_, rule, err = resolver.ResolveFeeRule(context.Background(), &otherOrg, model.TriggerCapture, now, nil)
if err != nil {
t.Fatalf("expected global fallback for other org, got error: %v", err)
}
if rule.RuleID != "global_capture" {
t.Fatalf("expected global rule, got %s", rule.RuleID)
}
}
func TestResolver_SelectsHighestPriority(t *testing.T) {
t.Helper()
now := time.Now()
org := bson.NewObjectID()
plan := &model.FeePlan{
Active: true,
EffectiveFrom: now.Add(-time.Hour),
Rules: []model.FeeRule{
{RuleID: "low", Trigger: model.TriggerCapture, Priority: 100, Percentage: "0.05", EffectiveFrom: now.Add(-time.Hour)},
{RuleID: "high", Trigger: model.TriggerCapture, Priority: 200, Percentage: "0.03", EffectiveFrom: now.Add(-time.Hour)},
},
}
plan.OrganizationRef = &org
store := &memoryPlansStore{plans: []*model.FeePlan{plan}}
resolver := New(store, zap.NewNop())
_, rule, err := resolver.ResolveFeeRule(context.Background(), &org, model.TriggerCapture, now, nil)
if err != nil {
t.Fatalf("expected rule resolution, got error: %v", err)
}
if rule.RuleID != "high" {
t.Fatalf("expected highest priority rule, got %s", rule.RuleID)
}
plan.Rules = append(plan.Rules, model.FeeRule{
RuleID: "conflict",
Trigger: model.TriggerCapture,
Priority: 200,
Percentage: "0.02",
EffectiveFrom: now.Add(-time.Hour),
})
if _, _, err := resolver.ResolveFeeRule(context.Background(), &org, model.TriggerCapture, now, nil); !errors.Is(err, ErrConflictingFeeRules) {
t.Fatalf("expected conflicting fee rules error, got %v", err)
}
}
func TestResolver_EffectiveDateFiltering(t *testing.T) {
t.Helper()
now := time.Now()
org := bson.NewObjectID()
past := now.Add(-24 * time.Hour)
future := now.Add(24 * time.Hour)
orgPlan := &model.FeePlan{
Active: true,
EffectiveFrom: past,
Rules: []model.FeeRule{
{RuleID: "expired", Trigger: model.TriggerCapture, Priority: 100, Percentage: "0.05", EffectiveFrom: past, EffectiveTo: &past},
},
}
orgPlan.OrganizationRef = &org
globalPlan := &model.FeePlan{
Active: true,
EffectiveFrom: past,
Rules: []model.FeeRule{
{RuleID: "current", Trigger: model.TriggerCapture, Priority: 100, Percentage: "0.05", EffectiveFrom: past, EffectiveTo: &future},
},
}
store := &memoryPlansStore{plans: []*model.FeePlan{orgPlan, globalPlan}}
resolver := New(store, zap.NewNop())
_, rule, err := resolver.ResolveFeeRule(context.Background(), &org, model.TriggerCapture, now, nil)
if err != nil {
t.Fatalf("expected fallback to global, got error: %v", err)
}
if rule.RuleID != "current" {
t.Fatalf("expected current global rule, got %s", rule.RuleID)
}
}
func TestResolver_AppliesToFiltering(t *testing.T) {
t.Helper()
now := time.Now()
plan := &model.FeePlan{
Active: true,
EffectiveFrom: now.Add(-time.Hour),
Rules: []model.FeeRule{
{RuleID: "card", Trigger: model.TriggerCapture, Priority: 200, Percentage: "0.03", AppliesTo: map[string]string{"paymentMethod": "card"}, EffectiveFrom: now.Add(-time.Hour)},
{RuleID: "default", Trigger: model.TriggerCapture, Priority: 100, Percentage: "0.05", EffectiveFrom: now.Add(-time.Hour)},
},
}
store := &memoryPlansStore{plans: []*model.FeePlan{plan}}
resolver := New(store, zap.NewNop())
_, rule, err := resolver.ResolveFeeRule(context.Background(), nil, model.TriggerCapture, now, map[string]string{"paymentMethod": "card"})
if err != nil {
t.Fatalf("expected card rule, got error: %v", err)
}
if rule.RuleID != "card" {
t.Fatalf("expected card rule, got %s", rule.RuleID)
}
_, rule, err = resolver.ResolveFeeRule(context.Background(), nil, model.TriggerCapture, now, map[string]string{"paymentMethod": "bank"})
if err != nil {
t.Fatalf("expected default rule, got error: %v", err)
}
if rule.RuleID != "default" {
t.Fatalf("expected default rule, got %s", rule.RuleID)
}
}
func TestResolver_AppliesToFilteringSupportsListsAndWildcard(t *testing.T) {
t.Helper()
now := time.Now()
plan := &model.FeePlan{
Active: true,
EffectiveFrom: now.Add(-time.Hour),
Rules: []model.FeeRule{
{RuleID: "network_multi", Trigger: model.TriggerCapture, Priority: 300, Percentage: "0.03", AppliesTo: map[string]string{"network": "tron, solana"}, EffectiveFrom: now.Add(-time.Hour)},
{RuleID: "asset_any", Trigger: model.TriggerCapture, Priority: 200, Percentage: "0.02", AppliesTo: map[string]string{"asset": "*"}, EffectiveFrom: now.Add(-time.Hour)},
{RuleID: "default", Trigger: model.TriggerCapture, Priority: 100, Percentage: "0.05", EffectiveFrom: now.Add(-time.Hour)},
},
}
store := &memoryPlansStore{plans: []*model.FeePlan{plan}}
resolver := New(store, zap.NewNop())
_, rule, err := resolver.ResolveFeeRule(context.Background(), nil, model.TriggerCapture, now, map[string]string{"network": "tron"})
if err != nil {
t.Fatalf("expected list match rule, got error: %v", err)
}
if rule.RuleID != "network_multi" {
t.Fatalf("expected network list rule, got %s", rule.RuleID)
}
_, rule, err = resolver.ResolveFeeRule(context.Background(), nil, model.TriggerCapture, now, map[string]string{"asset": "USDT"})
if err != nil {
t.Fatalf("expected wildcard rule, got error: %v", err)
}
if rule.RuleID != "asset_any" {
t.Fatalf("expected asset wildcard rule, got %s", rule.RuleID)
}
_, rule, err = resolver.ResolveFeeRule(context.Background(), nil, model.TriggerCapture, now, map[string]string{"network": "eth"})
if err != nil {
t.Fatalf("expected default rule, got error: %v", err)
}
if rule.RuleID != "default" {
t.Fatalf("expected default rule, got %s", rule.RuleID)
}
}
func TestResolver_MissingTriggerReturnsErr(t *testing.T) {
t.Helper()
now := time.Now()
plan := &model.FeePlan{
Active: true,
EffectiveFrom: now.Add(-time.Hour),
Rules: []model.FeeRule{
{RuleID: "capture", Trigger: model.TriggerCapture, Priority: 10, Percentage: "0.05", EffectiveFrom: now.Add(-time.Hour)},
},
}
store := &memoryPlansStore{plans: []*model.FeePlan{plan}}
resolver := New(store, zap.NewNop())
if _, _, err := resolver.ResolveFeeRule(context.Background(), nil, model.TriggerRefund, now, nil); !errors.Is(err, ErrNoFeeRuleFound) {
t.Fatalf("expected ErrNoFeeRuleFound, got %v", err)
}
}
func TestResolver_MultipleActivePlansConflict(t *testing.T) {
t.Helper()
now := time.Now()
org := bson.NewObjectID()
p1 := &model.FeePlan{
Active: true,
EffectiveFrom: now.Add(-time.Hour),
Rules: []model.FeeRule{
{RuleID: "r1", Trigger: model.TriggerCapture, Priority: 10, Percentage: "0.05", EffectiveFrom: now.Add(-time.Hour)},
},
}
p1.OrganizationRef = &org
p2 := &model.FeePlan{
Active: true,
EffectiveFrom: now.Add(-30 * time.Minute),
Rules: []model.FeeRule{
{RuleID: "r2", Trigger: model.TriggerCapture, Priority: 20, Percentage: "0.03", EffectiveFrom: now.Add(-time.Hour)},
},
}
p2.OrganizationRef = &org
store := &memoryPlansStore{plans: []*model.FeePlan{p1, p2}}
resolver := New(store, zap.NewNop())
if _, _, err := resolver.ResolveFeeRule(context.Background(), &org, model.TriggerCapture, now, nil); !errors.Is(err, storage.ErrConflictingFeePlans) {
t.Fatalf("expected conflicting plans error, got %v", err)
}
}
type memoryPlansStore struct {
plans []*model.FeePlan
}
func (m *memoryPlansStore) Create(context.Context, *model.FeePlan) error { return nil }
func (m *memoryPlansStore) Update(context.Context, *model.FeePlan) error { return nil }
func (m *memoryPlansStore) Get(context.Context, bson.ObjectID) (*model.FeePlan, error) {
return nil, storage.ErrFeePlanNotFound
}
func (m *memoryPlansStore) GetActivePlan(ctx context.Context, orgRef bson.ObjectID, at time.Time) (*model.FeePlan, error) {
if !orgRef.IsZero() {
if plan, err := m.FindActiveOrgPlan(ctx, orgRef, at); err == nil {
return plan, nil
} else if !errors.Is(err, storage.ErrFeePlanNotFound) {
return nil, err
}
}
return m.FindActiveGlobalPlan(ctx, at)
}
func (m *memoryPlansStore) FindActiveOrgPlan(_ context.Context, orgRef bson.ObjectID, at time.Time) (*model.FeePlan, error) {
var matches []*model.FeePlan
for _, plan := range m.plans {
if plan == nil || plan.OrganizationRef == nil || plan.OrganizationRef.IsZero() || (*plan.OrganizationRef != orgRef) {
continue
}
if !plan.Active {
continue
}
if plan.EffectiveFrom.After(at) {
continue
}
if plan.EffectiveTo != nil && !plan.EffectiveTo.After(at) {
continue
}
matches = append(matches, plan)
}
if len(matches) == 0 {
return nil, storage.ErrFeePlanNotFound
}
if len(matches) > 1 {
return nil, storage.ErrConflictingFeePlans
}
return matches[0], nil
}
func (m *memoryPlansStore) FindActiveGlobalPlan(_ context.Context, at time.Time) (*model.FeePlan, error) {
var matches []*model.FeePlan
for _, plan := range m.plans {
if plan == nil || ((plan.OrganizationRef != nil) && !plan.OrganizationRef.IsZero()) {
continue
}
if !plan.Active {
continue
}
if plan.EffectiveFrom.After(at) {
continue
}
if plan.EffectiveTo != nil && !plan.EffectiveTo.After(at) {
continue
}
matches = append(matches, plan)
}
if len(matches) == 0 {
return nil, storage.ErrFeePlanNotFound
}
if len(matches) > 1 {
return nil, storage.ErrConflictingFeePlans
}
return matches[0], nil
}
var _ storage.PlansStore = (*memoryPlansStore)(nil)

View File

@@ -0,0 +1,88 @@
package fees
import (
"strings"
"time"
feesv1 "github.com/tech/sendico/pkg/proto/billing/fees/v1"
tracev1 "github.com/tech/sendico/pkg/proto/common/trace/v1"
"go.uber.org/zap"
)
func requestLogFields(meta *feesv1.RequestMeta, intent *feesv1.Intent) []zap.Field {
fields := logFieldsFromRequestMeta(meta)
fields = append(fields, logFieldsFromIntent(intent)...)
return fields
}
func logFieldsFromRequestMeta(meta *feesv1.RequestMeta) []zap.Field {
if meta == nil {
return nil
}
fields := make([]zap.Field, 0, 4)
if org := strings.TrimSpace(meta.GetOrganizationRef()); org != "" {
fields = append(fields, zap.String("organization_ref", org))
}
fields = append(fields, logFieldsFromTrace(meta.GetTrace())...)
return fields
}
func logFieldsFromIntent(intent *feesv1.Intent) []zap.Field {
if intent == nil {
return nil
}
fields := make([]zap.Field, 0, 5)
if trigger := intent.GetTrigger(); trigger != feesv1.Trigger_TRIGGER_UNSPECIFIED {
fields = append(fields, zap.String("trigger", trigger.String()))
}
if base := intent.GetBaseAmount(); base != nil {
if amount := strings.TrimSpace(base.GetAmount()); amount != "" {
fields = append(fields, zap.String("base_amount", amount))
}
if currency := strings.TrimSpace(base.GetCurrency()); currency != "" {
fields = append(fields, zap.String("base_currency", currency))
}
}
if booked := intent.GetBookedAt(); booked != nil && booked.IsValid() {
fields = append(fields, zap.Time("booked_at", booked.AsTime()))
}
if attrs := intent.GetAttributes(); len(attrs) > 0 {
fields = append(fields, zap.Int("attributes_count", len(attrs)))
}
return fields
}
func logFieldsFromTrace(trace *tracev1.TraceContext) []zap.Field {
if trace == nil {
return nil
}
fields := make([]zap.Field, 0, 3)
if reqRef := strings.TrimSpace(trace.GetRequestRef()); reqRef != "" {
fields = append(fields, zap.String("request_ref", reqRef))
}
if idem := strings.TrimSpace(trace.GetIdempotencyKey()); idem != "" {
fields = append(fields, zap.String("idempotency_key", idem))
}
if traceRef := strings.TrimSpace(trace.GetTraceRef()); traceRef != "" {
fields = append(fields, zap.String("trace_ref", traceRef))
}
return fields
}
func logFieldsFromTokenPayload(payload *feeQuoteTokenPayload) []zap.Field {
if payload == nil {
return nil
}
fields := make([]zap.Field, 0, 6)
if org := strings.TrimSpace(payload.OrganizationRef); org != "" {
fields = append(fields, zap.String("organization_ref", org))
}
if payload.ExpiresAtUnixMs > 0 {
fields = append(fields,
zap.Int64("expires_at_unix_ms", payload.ExpiresAtUnixMs),
zap.Time("expires_at", time.UnixMilli(payload.ExpiresAtUnixMs)))
}
fields = append(fields, logFieldsFromIntent(payload.Intent)...)
fields = append(fields, logFieldsFromTrace(payload.Trace)...)
return fields
}

View File

@@ -0,0 +1,71 @@
package fees
import (
"strconv"
"strings"
"sync"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
feesv1 "github.com/tech/sendico/pkg/proto/billing/fees/v1"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
var (
metricsOnce sync.Once
quoteRequestsTotal *prometheus.CounterVec
quoteLatency *prometheus.HistogramVec
)
func initMetrics() {
metricsOnce.Do(func() {
quoteRequestsTotal = promauto.NewCounterVec(
prometheus.CounterOpts{
Namespace: "billing",
Subsystem: "fees",
Name: "requests_total",
Help: "Total number of fee service requests processed.",
},
[]string{"call", "trigger", "status", "fx_used"},
)
quoteLatency = promauto.NewHistogramVec(
prometheus.HistogramOpts{
Namespace: "billing",
Subsystem: "fees",
Name: "request_latency_seconds",
Help: "Latency of fee service requests.",
Buckets: prometheus.DefBuckets,
},
[]string{"call", "trigger", "status", "fx_used"},
)
})
}
func observeMetrics(call string, trigger feesv1.Trigger, statusLabel string, fxUsed bool, took time.Duration) {
triggerLabel := trigger.String()
if trigger == feesv1.Trigger_TRIGGER_UNSPECIFIED {
triggerLabel = "TRIGGER_UNSPECIFIED"
}
fxLabel := strconv.FormatBool(fxUsed)
quoteRequestsTotal.WithLabelValues(call, triggerLabel, statusLabel, fxLabel).Inc()
quoteLatency.WithLabelValues(call, triggerLabel, statusLabel, fxLabel).Observe(took.Seconds())
}
func statusFromError(err error) string {
if err == nil {
return "success"
}
st, ok := status.FromError(err)
if !ok {
return "error"
}
code := st.Code()
if code == codes.OK {
return "success"
}
return strings.ToLower(code.String())
}

View File

@@ -0,0 +1,57 @@
package fees
import (
"strings"
internalcalculator "github.com/tech/sendico/billing/fees/internal/service/fees/internal/calculator"
oracleclient "github.com/tech/sendico/fx/oracle/client"
clockpkg "github.com/tech/sendico/pkg/clock"
)
// Option configures a Service instance.
type Option func(*Service)
// WithClock sets a custom clock implementation.
func WithClock(clock clockpkg.Clock) Option {
return func(s *Service) {
if clock != nil {
s.clock = clock
}
}
}
// WithCalculator sets a custom calculator implementation.
func WithCalculator(calculator Calculator) Option {
return func(s *Service) {
if calculator != nil {
s.calculator = calculator
}
}
}
// WithOracleClient wires an FX oracle client for FX trigger evaluations.
func WithOracleClient(oracle oracleclient.Client) Option {
return func(s *Service) {
s.oracle = oracle
// Rebuild default calculator if none was injected.
if s.calculator == nil {
s.calculator = internalcalculator.New(s.logger, oracle)
}
}
}
// WithFeeResolver injects a custom fee resolver (useful for tests).
func WithFeeResolver(r FeeResolver) Option {
return func(s *Service) {
if r != nil {
s.resolver = r
}
}
}
// WithDiscoveryInvokeURI sets the invoke URI used when announcing the service in discovery.
func WithDiscoveryInvokeURI(invokeURI string) Option {
return func(s *Service) {
s.invokeURI = strings.TrimSpace(invokeURI)
}
}

View File

@@ -0,0 +1,15 @@
package fees
import (
"context"
"time"
"github.com/tech/sendico/billing/fees/storage/model"
"go.mongodb.org/mongo-driver/v2/bson"
)
// FeeResolver centralises plan/rule resolution with org override and global fallback.
// Implementations live under the internal/resolver package.
type FeeResolver interface {
ResolveFeeRule(ctx context.Context, orgID *bson.ObjectID, trigger model.Trigger, at time.Time, attrs map[string]string) (*model.FeePlan, *model.FeeRule, error)
}

View File

@@ -0,0 +1,496 @@
package fees
import (
"context"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"strings"
"time"
"github.com/tech/sendico/billing/fees/internal/appversion"
internalcalculator "github.com/tech/sendico/billing/fees/internal/service/fees/internal/calculator"
"github.com/tech/sendico/billing/fees/internal/service/fees/internal/resolver"
"github.com/tech/sendico/billing/fees/storage"
"github.com/tech/sendico/billing/fees/storage/model"
oracleclient "github.com/tech/sendico/fx/oracle/client"
"github.com/tech/sendico/pkg/api/routers"
clockpkg "github.com/tech/sendico/pkg/clock"
"github.com/tech/sendico/pkg/discovery"
"github.com/tech/sendico/pkg/merrors"
msg "github.com/tech/sendico/pkg/messaging"
"github.com/tech/sendico/pkg/mlogger"
"github.com/tech/sendico/pkg/mservice"
feesv1 "github.com/tech/sendico/pkg/proto/billing/fees/v1"
tracev1 "github.com/tech/sendico/pkg/proto/common/trace/v1"
"go.mongodb.org/mongo-driver/v2/bson"
"go.uber.org/zap"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb"
)
type Service struct {
logger mlogger.Logger
storage storage.Repository
producer msg.Producer
clock clockpkg.Clock
calculator Calculator
oracle oracleclient.Client
resolver FeeResolver
announcer *discovery.Announcer
invokeURI string
feesv1.UnimplementedFeeEngineServer
}
func NewService(logger mlogger.Logger, repo storage.Repository, producer msg.Producer, opts ...Option) *Service {
svc := &Service{
logger: logger.Named("fees"),
storage: repo,
producer: producer,
clock: clockpkg.NewSystem(),
}
initMetrics()
for _, opt := range opts {
opt(svc)
}
if svc.clock == nil {
svc.clock = clockpkg.NewSystem()
}
if svc.calculator == nil {
svc.calculator = internalcalculator.New(svc.logger, svc.oracle)
}
if svc.resolver == nil {
svc.resolver = resolver.New(repo.Plans(), svc.logger)
}
svc.startDiscoveryAnnouncer()
return svc
}
func (s *Service) Register(router routers.GRPC) error {
return router.Register(func(reg grpc.ServiceRegistrar) {
feesv1.RegisterFeeEngineServer(reg, s)
})
}
func (s *Service) Shutdown() {
if s == nil {
return
}
if s.announcer != nil {
s.announcer.Stop()
}
}
func (s *Service) startDiscoveryAnnouncer() {
if s == nil || s.producer == nil {
return
}
announce := discovery.Announcement{
Service: "BILLING_FEES",
Operations: []string{"fee.calc"},
InvokeURI: s.invokeURI,
Version: appversion.Create().Short(),
}
s.announcer = discovery.NewAnnouncer(s.logger, s.producer, string(mservice.FeePlans), announce)
s.announcer.Start()
}
func (s *Service) QuoteFees(ctx context.Context, req *feesv1.QuoteFeesRequest) (resp *feesv1.QuoteFeesResponse, err error) {
var (
meta *feesv1.RequestMeta
intent *feesv1.Intent
)
if req != nil {
meta = req.GetMeta()
intent = req.GetIntent()
}
logger := s.logger.With(requestLogFields(meta, intent)...)
start := s.clock.Now()
trigger := feesv1.Trigger_TRIGGER_UNSPECIFIED
if intent != nil {
trigger = intent.GetTrigger()
}
var fxUsed bool
defer func() {
statusLabel := statusFromError(err)
linesCount := 0
appliedCount := 0
if err == nil && resp != nil {
fxUsed = resp.GetFxUsed() != nil
linesCount = len(resp.GetLines())
appliedCount = len(resp.GetApplied())
}
observeMetrics("quote", trigger, statusLabel, fxUsed, time.Since(start))
logFields := []zap.Field{
zap.String("status", statusLabel),
zap.Duration("duration", time.Since(start)),
zap.Bool("fx_used", fxUsed),
zap.String("trigger", trigger.String()),
zap.Int("lines", linesCount),
zap.Int("applied_rules", appliedCount),
}
if err != nil {
logger.Warn("QuoteFees finished", append(logFields, zap.Error(err))...)
return
}
logger.Info("QuoteFees finished", logFields...)
}()
logger.Debug("QuoteFees request received")
if err = s.validateQuoteRequest(req); err != nil {
return nil, err
}
orgRef, parseErr := bson.ObjectIDFromHex(req.GetMeta().GetOrganizationRef())
if parseErr != nil {
logger.Warn("QuoteFees invalid organization_ref", zap.Error(parseErr))
err = status.Error(codes.InvalidArgument, "invalid organization_ref")
return nil, err
}
lines, applied, fx, computeErr := s.computeQuote(ctx, orgRef, req.GetIntent(), req.GetPolicy(), req.GetMeta().GetTrace())
if computeErr != nil {
err = computeErr
return nil, err
}
resp = &feesv1.QuoteFeesResponse{
Meta: &feesv1.ResponseMeta{Trace: req.GetMeta().GetTrace()},
Lines: lines,
Applied: applied,
FxUsed: fx,
}
return resp, nil
}
func (s *Service) PrecomputeFees(ctx context.Context, req *feesv1.PrecomputeFeesRequest) (resp *feesv1.PrecomputeFeesResponse, err error) {
var (
meta *feesv1.RequestMeta
intent *feesv1.Intent
)
if req != nil {
meta = req.GetMeta()
intent = req.GetIntent()
}
logger := s.logger.With(requestLogFields(meta, intent)...)
start := s.clock.Now()
trigger := feesv1.Trigger_TRIGGER_UNSPECIFIED
if intent != nil {
trigger = intent.GetTrigger()
}
var (
fxUsed bool
expiresAt time.Time
)
defer func() {
statusLabel := statusFromError(err)
linesCount := 0
appliedCount := 0
if err == nil && resp != nil {
fxUsed = resp.GetFxUsed() != nil
linesCount = len(resp.GetLines())
appliedCount = len(resp.GetApplied())
if ts := resp.GetExpiresAt(); ts != nil {
expiresAt = ts.AsTime()
}
}
observeMetrics("precompute", trigger, statusLabel, fxUsed, time.Since(start))
logFields := []zap.Field{
zap.String("status", statusLabel),
zap.Duration("duration", time.Since(start)),
zap.Bool("fx_used", fxUsed),
zap.String("trigger", trigger.String()),
zap.Int("lines", linesCount),
zap.Int("applied_rules", appliedCount),
}
if !expiresAt.IsZero() {
logFields = append(logFields, zap.Time("expires_at", expiresAt))
}
if err != nil {
logger.Warn("PrecomputeFees finished", append(logFields, zap.Error(err))...)
return
}
logger.Info("PrecomputeFees finished", logFields...)
}()
logger.Debug("PrecomputeFees request received")
if err = s.validatePrecomputeRequest(req); err != nil {
return nil, err
}
now := s.clock.Now()
orgRef, parseErr := bson.ObjectIDFromHex(req.GetMeta().GetOrganizationRef())
if parseErr != nil {
logger.Warn("PrecomputeFees invalid organization_ref", zap.Error(parseErr))
err = status.Error(codes.InvalidArgument, "invalid organization_ref")
return nil, err
}
lines, applied, fx, computeErr := s.computeQuoteWithTime(ctx, orgRef, req.GetIntent(), nil, req.GetMeta().GetTrace(), now)
if computeErr != nil {
err = computeErr
return nil, err
}
ttl := req.GetTtlMs()
if ttl <= 0 {
ttl = 60000
}
expiresAt = now.Add(time.Duration(ttl) * time.Millisecond)
payload := feeQuoteTokenPayload{
OrganizationRef: req.GetMeta().GetOrganizationRef(),
Intent: req.GetIntent(),
ExpiresAtUnixMs: expiresAt.UnixMilli(),
Trace: req.GetMeta().GetTrace(),
}
var token string
if token, err = encodeTokenPayload(payload); err != nil {
logger.Warn("failed to encode fee quote token", zap.Error(err))
err = status.Error(codes.Internal, "failed to encode fee quote token")
return nil, err
}
resp = &feesv1.PrecomputeFeesResponse{
Meta: &feesv1.ResponseMeta{Trace: req.GetMeta().GetTrace()},
FeeQuoteToken: token,
ExpiresAt: timestamppb.New(expiresAt),
Lines: lines,
Applied: applied,
FxUsed: fx,
}
return resp, nil
}
func (s *Service) ValidateFeeToken(ctx context.Context, req *feesv1.ValidateFeeTokenRequest) (resp *feesv1.ValidateFeeTokenResponse, err error) {
tokenLen := 0
if req != nil {
tokenLen = len(strings.TrimSpace(req.GetFeeQuoteToken()))
}
logger := s.logger.With(zap.Int("token_length", tokenLen))
start := s.clock.Now()
trigger := feesv1.Trigger_TRIGGER_UNSPECIFIED
var (
fxUsed bool
resultReason string
)
defer func() {
statusLabel := statusFromError(err)
if err == nil && resp != nil {
if !resp.GetValid() {
statusLabel = "invalid"
}
fxUsed = resp.GetFxUsed() != nil
if resp.GetIntent() != nil {
trigger = resp.GetIntent().GetTrigger()
}
}
observeMetrics("validate", trigger, statusLabel, fxUsed, time.Since(start))
logFields := []zap.Field{
zap.String("status", statusLabel),
zap.Duration("duration", time.Since(start)),
zap.Bool("fx_used", fxUsed),
zap.String("trigger", trigger.String()),
zap.Bool("valid", resp != nil && resp.GetValid()),
}
if resultReason != "" {
logFields = append(logFields, zap.String("reason", resultReason))
}
if err != nil {
logger.Warn("ValidateFeeToken finished", append(logFields, zap.Error(err))...)
return
}
logger.Info("ValidateFeeToken finished", logFields...)
}()
logger.Debug("ValidateFeeToken request received")
if req == nil || strings.TrimSpace(req.GetFeeQuoteToken()) == "" {
resultReason = "missing_token"
err = status.Error(codes.InvalidArgument, "fee_quote_token is required")
return nil, err
}
now := s.clock.Now()
payload, decodeErr := decodeTokenPayload(req.GetFeeQuoteToken())
if decodeErr != nil {
resultReason = "invalid_token"
logger.Warn("failed to decode fee quote token", zap.Error(decodeErr))
resp = &feesv1.ValidateFeeTokenResponse{Meta: &feesv1.ResponseMeta{}, Valid: false, Reason: "invalid_token"}
return resp, nil
}
logger = logger.With(logFieldsFromTokenPayload(&payload)...)
if payload.Intent != nil {
trigger = payload.Intent.GetTrigger()
}
if now.UnixMilli() > payload.ExpiresAtUnixMs {
resultReason = "expired"
logger.Info("fee quote token expired")
resp = &feesv1.ValidateFeeTokenResponse{Meta: &feesv1.ResponseMeta{}, Valid: false, Reason: "expired"}
return resp, nil
}
orgRef, parseErr := bson.ObjectIDFromHex(payload.OrganizationRef)
if parseErr != nil {
resultReason = "invalid_token"
logger.Warn("token contained invalid organization reference", zap.Error(parseErr))
resp = &feesv1.ValidateFeeTokenResponse{Meta: &feesv1.ResponseMeta{}, Valid: false, Reason: "invalid_token"}
return resp, nil
}
lines, applied, fx, computeErr := s.computeQuoteWithTime(ctx, orgRef, payload.Intent, nil, payload.Trace, now)
if computeErr != nil {
err = computeErr
return nil, err
}
resp = &feesv1.ValidateFeeTokenResponse{
Meta: &feesv1.ResponseMeta{Trace: payload.Trace},
Valid: true,
Intent: payload.Intent,
Lines: lines,
Applied: applied,
FxUsed: fx,
}
return resp, nil
}
func (s *Service) validateQuoteRequest(req *feesv1.QuoteFeesRequest) error {
if req == nil {
return status.Error(codes.InvalidArgument, "request is required")
}
if req.GetMeta() == nil || strings.TrimSpace(req.GetMeta().GetOrganizationRef()) == "" {
return status.Error(codes.InvalidArgument, "meta.organization_ref is required")
}
if req.GetIntent() == nil {
return status.Error(codes.InvalidArgument, "intent is required")
}
if req.GetIntent().GetTrigger() == feesv1.Trigger_TRIGGER_UNSPECIFIED {
return status.Error(codes.InvalidArgument, "intent.trigger is required")
}
if req.GetIntent().GetBaseAmount() == nil {
return status.Error(codes.InvalidArgument, "intent.base_amount is required")
}
if strings.TrimSpace(req.GetIntent().GetBaseAmount().GetAmount()) == "" {
return status.Error(codes.InvalidArgument, "intent.base_amount.amount is required")
}
if strings.TrimSpace(req.GetIntent().GetBaseAmount().GetCurrency()) == "" {
return status.Error(codes.InvalidArgument, "intent.base_amount.currency is required")
}
return nil
}
func (s *Service) validatePrecomputeRequest(req *feesv1.PrecomputeFeesRequest) error {
if req == nil {
return status.Error(codes.InvalidArgument, "request is required")
}
return s.validateQuoteRequest(&feesv1.QuoteFeesRequest{Meta: req.GetMeta(), Intent: req.GetIntent()})
}
func (s *Service) computeQuote(ctx context.Context, orgRef bson.ObjectID, intent *feesv1.Intent, overrides *feesv1.PolicyOverrides, trace *tracev1.TraceContext) ([]*feesv1.DerivedPostingLine, []*feesv1.AppliedRule, *feesv1.FXUsed, error) {
return s.computeQuoteWithTime(ctx, orgRef, intent, overrides, trace, s.clock.Now())
}
func (s *Service) computeQuoteWithTime(ctx context.Context, orgRef bson.ObjectID, intent *feesv1.Intent, _ *feesv1.PolicyOverrides, trace *tracev1.TraceContext, now time.Time) ([]*feesv1.DerivedPostingLine, []*feesv1.AppliedRule, *feesv1.FXUsed, error) {
bookedAt := now
if intent.GetBookedAt() != nil && intent.GetBookedAt().IsValid() {
bookedAt = intent.GetBookedAt().AsTime()
}
logFields := []zap.Field{
zap.Time("booked_at_used", bookedAt),
}
if !orgRef.IsZero() {
logFields = append(logFields, zap.String("organization_ref", orgRef.Hex()))
}
logFields = append(logFields, logFieldsFromIntent(intent)...)
logFields = append(logFields, logFieldsFromTrace(trace)...)
logger := s.logger.With(logFields...)
var orgPtr *bson.ObjectID
if !orgRef.IsZero() {
orgPtr = &orgRef
}
plan, rule, err := s.resolver.ResolveFeeRule(ctx, orgPtr, convertTrigger(intent.GetTrigger()), bookedAt, intent.GetAttributes())
if err != nil {
s.logger.Warn("Failed to resolve fee rule", zap.Error(err))
switch {
case errors.Is(err, merrors.ErrNoData):
return nil, nil, nil, status.Error(codes.NotFound, fmt.Sprintf("fee rule not found: %s", err.Error()))
case errors.Is(err, merrors.ErrDataConflict):
return nil, nil, nil, status.Error(codes.FailedPrecondition, fmt.Sprintf("conflicting fee rules: %s", err.Error()))
case errors.Is(err, storage.ErrConflictingFeePlans):
return nil, nil, nil, status.Error(codes.FailedPrecondition, fmt.Sprintf("conflicting fee plans: %s", err.Error()))
case errors.Is(err, storage.ErrFeePlanNotFound):
return nil, nil, nil, status.Error(codes.NotFound, fmt.Sprintf("fee plan not found: %s", err.Error()))
default:
return nil, nil, nil, status.Error(codes.Internal, fmt.Sprintf("failed to resolve fee rule: %s", err.Error()))
}
}
originalRules := plan.Rules
plan.Rules = []model.FeeRule{*rule}
defer func() {
plan.Rules = originalRules
}()
result, calcErr := s.calculator.Compute(ctx, plan, intent, bookedAt, trace)
if calcErr != nil {
if errors.Is(calcErr, merrors.ErrInvalidArg) {
return nil, nil, nil, status.Error(codes.InvalidArgument, calcErr.Error())
}
logger.Warn("failed to compute fee quote", zap.Error(calcErr))
return nil, nil, nil, status.Error(codes.Internal, "failed to compute fee quote")
}
return result.Lines, result.Applied, result.FxUsed, nil
}
type feeQuoteTokenPayload struct {
OrganizationRef string `json:"organization_ref"`
Intent *feesv1.Intent `json:"intent"`
ExpiresAtUnixMs int64 `json:"expires_at_unix_ms"`
Trace *tracev1.TraceContext `json:"trace,omitempty"`
}
func encodeTokenPayload(payload feeQuoteTokenPayload) (string, error) {
data, err := json.Marshal(payload)
if err != nil {
return "", merrors.Internal("fees: failed to serialize token payload")
}
return base64.StdEncoding.EncodeToString(data), nil
}
func decodeTokenPayload(token string) (feeQuoteTokenPayload, error) {
var payload feeQuoteTokenPayload
data, err := base64.StdEncoding.DecodeString(token)
if err != nil {
return payload, merrors.InvalidArgument("fees: invalid token encoding")
}
if err := json.Unmarshal(data, &payload); err != nil {
return payload, merrors.InvalidArgument("fees: invalid token payload")
}
return payload, nil
}

View File

@@ -0,0 +1,516 @@
package fees
import (
"context"
"errors"
"testing"
"time"
"github.com/tech/sendico/billing/fees/internal/service/fees/types"
"github.com/tech/sendico/billing/fees/storage"
"github.com/tech/sendico/billing/fees/storage/model"
oracleclient "github.com/tech/sendico/fx/oracle/client"
me "github.com/tech/sendico/pkg/messaging/envelope"
feesv1 "github.com/tech/sendico/pkg/proto/billing/fees/v1"
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
tracev1 "github.com/tech/sendico/pkg/proto/common/trace/v1"
"go.mongodb.org/mongo-driver/v2/bson"
"go.uber.org/zap"
"google.golang.org/protobuf/types/known/timestamppb"
)
func TestQuoteFees_ComputesDerivedLines(t *testing.T) {
t.Helper()
now := time.Date(2024, 1, 10, 16, 0, 0, 0, time.UTC)
orgRef := bson.NewObjectID()
plan := &model.FeePlan{
Active: true,
EffectiveFrom: now.Add(-time.Hour),
Rules: []model.FeeRule{
{
RuleID: "capture_default",
Trigger: model.TriggerCapture,
Priority: 10,
Percentage: "0.029",
FixedAmount: "0.30",
LedgerAccountRef: "acct:fees",
LineType: "fee",
EntrySide: "credit",
Rounding: "half_up",
Metadata: map[string]string{
"scale": "2",
"tax_code": "VAT",
"tax_rate": "0.20",
},
EffectiveFrom: now.Add(-time.Hour),
},
},
}
plan.SetID(bson.NewObjectID())
plan.OrganizationRef = &orgRef
service := NewService(
zap.NewNop(),
&stubRepository{plans: &stubPlansStore{plan: plan}},
noopProducer{},
WithClock(fixedClock{now: now}),
)
req := &feesv1.QuoteFeesRequest{
Meta: &feesv1.RequestMeta{
OrganizationRef: orgRef.Hex(),
Trace: &tracev1.TraceContext{
TraceRef: "trace-capture",
},
},
Intent: &feesv1.Intent{
Trigger: feesv1.Trigger_TRIGGER_CAPTURE,
BaseAmount: &moneyv1.Money{
Amount: "100.00",
Currency: "USD",
},
BookedAt: timestamppb.New(now),
Attributes: map[string]string{"channel": "card"},
},
}
resp, err := service.QuoteFees(context.Background(), req)
if err != nil {
t.Fatalf("QuoteFees returned error: %v", err)
}
if resp.GetMeta().GetTrace().GetTraceRef() != "trace-capture" {
t.Fatalf("expected trace_ref to round-trip, got %q", resp.GetMeta().GetTrace().GetTraceRef())
}
if len(resp.GetLines()) != 1 {
t.Fatalf("expected 1 derived line, got %d", len(resp.GetLines()))
}
line := resp.GetLines()[0]
if got := line.GetMoney().GetAmount(); got != "3.20" {
t.Fatalf("expected fee amount 3.20, got %s", got)
}
if line.GetMoney().GetCurrency() != "USD" {
t.Fatalf("expected currency USD, got %s", line.GetMoney().GetCurrency())
}
if line.GetLedgerAccountRef() != "acct:fees" {
t.Fatalf("unexpected ledger account ref %s", line.GetLedgerAccountRef())
}
if meta := line.GetMeta(); meta["fee_rule_id"] != "capture_default" || meta["fee_plan_id"] != plan.GetID().Hex() || meta["tax_code"] != "VAT" {
t.Fatalf("unexpected derived line metadata: %#v", meta)
}
if len(resp.GetApplied()) != 1 {
t.Fatalf("expected 1 applied rule, got %d", len(resp.GetApplied()))
}
applied := resp.GetApplied()[0]
if applied.GetTaxCode() != "VAT" || applied.GetTaxRate() != "0.20" {
t.Fatalf("applied rule metadata mismatch: %+v", applied)
}
if applied.GetRounding() != moneyv1.RoundingMode_ROUND_HALF_UP {
t.Fatalf("expected rounding HALF_UP, got %v", applied.GetRounding())
}
if applied.GetParameters()["scale"] != "2" {
t.Fatalf("expected parameters to carry metadata scale, got %+v", applied.GetParameters())
}
}
func TestQuoteFees_FiltersByAttributesAndDates(t *testing.T) {
t.Helper()
now := time.Date(2024, 5, 20, 9, 30, 0, 0, time.UTC)
orgRef := bson.NewObjectID()
plan := &model.FeePlan{
Active: true,
EffectiveFrom: now.Add(-24 * time.Hour),
Rules: []model.FeeRule{
{
RuleID: "base",
Trigger: model.TriggerCapture,
Priority: 1,
Percentage: "0.10",
LedgerAccountRef: "acct:base",
Metadata: map[string]string{"scale": "2"},
Rounding: "half_even",
EffectiveFrom: now.Add(-time.Hour),
},
{
RuleID: "future",
Trigger: model.TriggerCapture,
Priority: 2,
Percentage: "0.50",
LedgerAccountRef: "acct:future",
Metadata: map[string]string{"scale": "2"},
Rounding: "half_even",
EffectiveFrom: now.Add(time.Hour),
},
{
RuleID: "attr",
Trigger: model.TriggerCapture,
Priority: 3,
Percentage: "0.30",
LedgerAccountRef: "acct:attr",
Metadata: map[string]string{"scale": "2"},
AppliesTo: map[string]string{"region": "eu"},
Rounding: "half_even",
EffectiveFrom: now.Add(-time.Hour),
},
},
}
plan.SetID(bson.NewObjectID())
plan.OrganizationRef = &orgRef
service := NewService(
zap.NewNop(),
&stubRepository{plans: &stubPlansStore{plan: plan}},
noopProducer{},
WithClock(fixedClock{now: now}),
)
req := &feesv1.QuoteFeesRequest{
Meta: &feesv1.RequestMeta{OrganizationRef: orgRef.Hex()},
Intent: &feesv1.Intent{
Trigger: feesv1.Trigger_TRIGGER_CAPTURE,
BaseAmount: &moneyv1.Money{
Amount: "50.00",
Currency: "EUR",
},
BookedAt: timestamppb.New(now),
Attributes: map[string]string{"region": "us"},
},
}
resp, err := service.QuoteFees(context.Background(), req)
if err != nil {
t.Fatalf("QuoteFees returned error: %v", err)
}
if len(resp.GetLines()) != 1 {
t.Fatalf("expected only base rule to fire, got %d lines", len(resp.GetLines()))
}
line := resp.GetLines()[0]
if line.GetLedgerAccountRef() != "acct:base" {
t.Fatalf("expected base rule to apply, got %s", line.GetLedgerAccountRef())
}
if line.GetMoney().GetAmount() != "5.00" {
t.Fatalf("expected 5.00 amount, got %s", line.GetMoney().GetAmount())
}
}
func TestQuoteFees_RoundingDown(t *testing.T) {
t.Helper()
now := time.Date(2024, 3, 15, 12, 0, 0, 0, time.UTC)
orgRef := bson.NewObjectID()
plan := &model.FeePlan{
Active: true,
EffectiveFrom: now.Add(-time.Hour),
Rules: []model.FeeRule{
{
RuleID: "round_down",
Trigger: model.TriggerCapture,
Priority: 1,
FixedAmount: "0.015",
LedgerAccountRef: "acct:round",
Metadata: map[string]string{"scale": "2"},
Rounding: "down",
EffectiveFrom: now.Add(-time.Hour),
},
},
}
plan.SetID(bson.NewObjectID())
plan.OrganizationRef = &orgRef
service := NewService(
zap.NewNop(),
&stubRepository{plans: &stubPlansStore{plan: plan}},
noopProducer{},
WithClock(fixedClock{now: now}),
)
req := &feesv1.QuoteFeesRequest{
Meta: &feesv1.RequestMeta{OrganizationRef: orgRef.Hex()},
Intent: &feesv1.Intent{
Trigger: feesv1.Trigger_TRIGGER_CAPTURE,
BaseAmount: &moneyv1.Money{
Amount: "1.00",
Currency: "USD",
},
BookedAt: timestamppb.New(now),
},
}
resp, err := service.QuoteFees(context.Background(), req)
if err != nil {
t.Fatalf("QuoteFees returned error: %v", err)
}
if len(resp.GetLines()) != 1 {
t.Fatalf("expected single derived line, got %d", len(resp.GetLines()))
}
if resp.GetLines()[0].GetMoney().GetAmount() != "0.01" {
t.Fatalf("expected rounding down to 0.01, got %s", resp.GetLines()[0].GetMoney().GetAmount())
}
}
func TestQuoteFees_UsesInjectedCalculator(t *testing.T) {
t.Helper()
now := time.Date(2024, 6, 1, 8, 0, 0, 0, time.UTC)
orgRef := bson.NewObjectID()
plan := &model.FeePlan{
Active: true,
EffectiveFrom: now.Add(-time.Hour),
Rules: []model.FeeRule{
{
RuleID: "stub",
Trigger: model.TriggerCapture,
Priority: 1,
Percentage: "0.01",
LedgerAccountRef: "acct:stub",
EffectiveFrom: now.Add(-time.Hour),
},
},
}
plan.SetID(bson.NewObjectID())
plan.OrganizationRef = &orgRef
result := &types.CalculationResult{
Lines: []*feesv1.DerivedPostingLine{
{
LedgerAccountRef: "acct:stub",
Money: &moneyv1.Money{
Amount: "1.23",
Currency: "USD",
},
},
},
Applied: []*feesv1.AppliedRule{
{RuleId: "stub"},
},
}
calc := &stubCalculator{result: result}
service := NewService(
zap.NewNop(),
&stubRepository{plans: &stubPlansStore{plan: plan}},
noopProducer{},
WithClock(fixedClock{now: now}),
WithCalculator(calc),
)
resp, err := service.QuoteFees(context.Background(), &feesv1.QuoteFeesRequest{
Meta: &feesv1.RequestMeta{OrganizationRef: orgRef.Hex()},
Intent: &feesv1.Intent{
Trigger: feesv1.Trigger_TRIGGER_CAPTURE,
BaseAmount: &moneyv1.Money{
Amount: "10.00",
Currency: "USD",
},
},
})
if err != nil {
t.Fatalf("QuoteFees returned error: %v", err)
}
if !calc.called {
t.Fatalf("expected calculator to be invoked")
}
if calc.gotPlan != plan {
t.Fatalf("expected calculator to receive plan pointer")
}
if len(resp.GetLines()) != len(result.Lines) {
t.Fatalf("expected %d lines, got %d", len(result.Lines), len(resp.GetLines()))
}
if resp.GetLines()[0].GetLedgerAccountRef() != "acct:stub" {
t.Fatalf("unexpected ledger account in response: %s", resp.GetLines()[0].GetLedgerAccountRef())
}
}
func TestQuoteFees_PopulatesFxUsed(t *testing.T) {
t.Helper()
now := time.Date(2024, 7, 1, 9, 30, 0, 0, time.UTC)
orgRef := bson.NewObjectID()
plan := &model.FeePlan{
Active: true,
EffectiveFrom: now.Add(-time.Hour),
Rules: []model.FeeRule{
{
RuleID: "fx_mark_up",
Trigger: model.TriggerFXConversion,
Priority: 1,
Percentage: "0.03",
LedgerAccountRef: "acct:fx",
Metadata: map[string]string{"scale": "2"},
Rounding: "half_even",
EffectiveFrom: now.Add(-time.Hour),
},
},
}
plan.SetID(bson.NewObjectID())
plan.OrganizationRef = &orgRef
fakeOracle := &oracleclient.Fake{
LatestRateFn: func(ctx context.Context, req oracleclient.LatestRateParams) (*oracleclient.RateSnapshot, error) {
return &oracleclient.RateSnapshot{
Pair: req.Pair,
Mid: "1.2300",
SpreadBps: "12",
Provider: "TestProvider",
RateRef: "rate-ref-123",
AsOf: now.Add(-2 * time.Minute),
}, nil
},
}
service := NewService(
zap.NewNop(),
&stubRepository{plans: &stubPlansStore{plan: plan}},
noopProducer{},
WithClock(fixedClock{now: now}),
WithOracleClient(fakeOracle),
)
resp, err := service.QuoteFees(context.Background(), &feesv1.QuoteFeesRequest{
Meta: &feesv1.RequestMeta{OrganizationRef: orgRef.Hex()},
Intent: &feesv1.Intent{
Trigger: feesv1.Trigger_TRIGGER_FX_CONVERSION,
BaseAmount: &moneyv1.Money{
Amount: "100.00",
Currency: "USD",
},
Attributes: map[string]string{
"fx_base_currency": "USD",
"fx_quote_currency": "EUR",
"fx_provider": "TestProvider",
"fx_side": "buy_base",
},
},
})
if err != nil {
t.Fatalf("QuoteFees returned error: %v", err)
}
if resp.GetFxUsed() == nil {
t.Fatalf("expected FxUsed to be populated")
}
fx := resp.GetFxUsed()
if fx.GetProvider() != "TestProvider" || fx.GetRate().GetValue() != "1.2300" {
t.Fatalf("unexpected FxUsed payload: %+v", fx)
}
if fx.GetPair().GetBase() != "USD" || fx.GetPair().GetQuote() != "EUR" {
t.Fatalf("unexpected currency pair: %+v", fx.GetPair())
}
}
type stubRepository struct {
plans storage.PlansStore
}
func (s *stubRepository) Ping(context.Context) error {
return nil
}
func (s *stubRepository) Plans() storage.PlansStore {
return s.plans
}
type stubPlansStore struct {
plan *model.FeePlan
globalPlan *model.FeePlan
}
func (s *stubPlansStore) Create(context.Context, *model.FeePlan) error {
return nil
}
func (s *stubPlansStore) Update(context.Context, *model.FeePlan) error {
return nil
}
func (s *stubPlansStore) Get(context.Context, bson.ObjectID) (*model.FeePlan, error) {
return nil, storage.ErrFeePlanNotFound
}
func (s *stubPlansStore) GetActivePlan(_ context.Context, orgRef bson.ObjectID, at time.Time) (*model.FeePlan, error) {
if !orgRef.IsZero() {
if plan, err := s.FindActiveOrgPlan(context.Background(), orgRef, at); err == nil {
return plan, nil
} else if !errors.Is(err, storage.ErrFeePlanNotFound) {
return nil, err
}
}
return s.FindActiveGlobalPlan(context.Background(), at)
}
func (s *stubPlansStore) FindActiveOrgPlan(_ context.Context, orgRef bson.ObjectID, at time.Time) (*model.FeePlan, error) {
if s.plan == nil {
return nil, storage.ErrFeePlanNotFound
}
if (s.plan.OrganizationRef != nil) && (*s.plan.OrganizationRef != orgRef) {
return nil, storage.ErrFeePlanNotFound
}
if !s.plan.Active {
return nil, storage.ErrFeePlanNotFound
}
if s.plan.EffectiveFrom.After(at) {
return nil, storage.ErrFeePlanNotFound
}
if s.plan.EffectiveTo != nil && !s.plan.EffectiveTo.After(at) {
return nil, storage.ErrFeePlanNotFound
}
return s.plan, nil
}
func (s *stubPlansStore) FindActiveGlobalPlan(_ context.Context, at time.Time) (*model.FeePlan, error) {
if s.globalPlan == nil {
return nil, storage.ErrFeePlanNotFound
}
if !s.globalPlan.Active {
return nil, storage.ErrFeePlanNotFound
}
if s.globalPlan.EffectiveFrom.After(at) {
return nil, storage.ErrFeePlanNotFound
}
if s.globalPlan.EffectiveTo != nil && !s.globalPlan.EffectiveTo.After(at) {
return nil, storage.ErrFeePlanNotFound
}
return s.globalPlan, nil
}
type noopProducer struct{}
func (noopProducer) SendMessage(me.Envelope) error {
return nil
}
type fixedClock struct {
now time.Time
}
func (f fixedClock) Now() time.Time {
return f.now
}
type stubCalculator struct {
result *types.CalculationResult
err error
called bool
gotPlan *model.FeePlan
bookedAt time.Time
}
func (s *stubCalculator) Compute(_ context.Context, plan *model.FeePlan, _ *feesv1.Intent, bookedAt time.Time, _ *tracev1.TraceContext) (*types.CalculationResult, error) {
s.called = true
s.gotPlan = plan
s.bookedAt = bookedAt
if s.err != nil {
return nil, s.err
}
return s.result, nil
}

View File

@@ -0,0 +1,23 @@
package fees
import (
"github.com/tech/sendico/billing/fees/storage/model"
feesv1 "github.com/tech/sendico/pkg/proto/billing/fees/v1"
)
func convertTrigger(trigger feesv1.Trigger) model.Trigger {
switch trigger {
case feesv1.Trigger_TRIGGER_CAPTURE:
return model.TriggerCapture
case feesv1.Trigger_TRIGGER_REFUND:
return model.TriggerRefund
case feesv1.Trigger_TRIGGER_DISPUTE:
return model.TriggerDispute
case feesv1.Trigger_TRIGGER_PAYOUT:
return model.TriggerPayout
case feesv1.Trigger_TRIGGER_FX_CONVERSION:
return model.TriggerFXConversion
default:
return model.TriggerUnspecified
}
}

View File

@@ -0,0 +1,12 @@
package types
import (
feesv1 "github.com/tech/sendico/pkg/proto/billing/fees/v1"
)
// CalculationResult contains derived fee lines and audit metadata.
type CalculationResult struct {
Lines []*feesv1.DerivedPostingLine
Applied []*feesv1.AppliedRule
FxUsed *feesv1.FXUsed
}

17
api/billing/fees/main.go Normal file
View File

@@ -0,0 +1,17 @@
package main
import (
"github.com/tech/sendico/billing/fees/internal/appversion"
si "github.com/tech/sendico/billing/fees/internal/server"
"github.com/tech/sendico/pkg/mlogger"
"github.com/tech/sendico/pkg/server"
smain "github.com/tech/sendico/pkg/server/main"
)
func factory(logger mlogger.Logger, file string, debug bool) (server.Application, error) {
return si.Create(logger, file, debug)
}
func main() {
smain.RunServer("main", appversion.Create(), factory)
}

View File

@@ -0,0 +1,63 @@
package model
import (
"time"
"github.com/tech/sendico/pkg/db/storable"
"github.com/tech/sendico/pkg/model"
"go.mongodb.org/mongo-driver/v2/bson"
)
const (
FeePlansCollection = "fee_plans"
)
// Trigger represents the event that causes a fee rule to apply.
type Trigger string
const (
TriggerUnspecified Trigger = "unspecified"
TriggerCapture Trigger = "capture"
TriggerRefund Trigger = "refund"
TriggerDispute Trigger = "dispute"
TriggerPayout Trigger = "payout"
TriggerFXConversion Trigger = "fx_conversion"
)
// FeePlan describes a collection of fee rules for an organisation.
type FeePlan struct {
storable.Base `bson:",inline" json:",inline"`
model.Describable `bson:",inline" json:",inline"`
OrganizationRef *bson.ObjectID `bson:"organizationRef,omitempty" json:"organizationRef,omitempty"`
Active bool `bson:"active" json:"active"`
EffectiveFrom time.Time `bson:"effectiveFrom" json:"effectiveFrom"`
EffectiveTo *time.Time `bson:"effectiveTo,omitempty" json:"effectiveTo,omitempty"`
Rules []FeeRule `bson:"rules,omitempty" json:"rules,omitempty"`
Metadata map[string]string `bson:"metadata,omitempty" json:"metadata,omitempty"`
}
// Collection implements storable.Storable.
func (*FeePlan) Collection() string {
return FeePlansCollection
}
// FeeRule represents a single pricing rule within a plan.
type FeeRule struct {
RuleID string `bson:"ruleId" json:"ruleId"`
Trigger Trigger `bson:"trigger" json:"trigger"`
Priority int `bson:"priority" json:"priority"`
Percentage string `bson:"percentage,omitempty" json:"percentage,omitempty"`
FixedAmount string `bson:"fixedAmount,omitempty" json:"fixedAmount,omitempty"`
Currency string `bson:"currency,omitempty" json:"currency,omitempty"`
MinimumAmount string `bson:"minimumAmount,omitempty" json:"minimumAmount,omitempty"`
MaximumAmount string `bson:"maximumAmount,omitempty" json:"maximumAmount,omitempty"`
AppliesTo map[string]string `bson:"appliesTo,omitempty" json:"appliesTo,omitempty"`
Formula string `bson:"formula,omitempty" json:"formula,omitempty"`
Metadata map[string]string `bson:"metadata,omitempty" json:"metadata,omitempty"`
LedgerAccountRef string `bson:"ledgerAccountRef,omitempty" json:"ledgerAccountRef,omitempty"`
LineType string `bson:"lineType,omitempty" json:"lineType,omitempty"`
EntrySide string `bson:"entrySide,omitempty" json:"entrySide,omitempty"`
Rounding string `bson:"rounding,omitempty" json:"rounding,omitempty"`
EffectiveFrom time.Time `bson:"effectiveFrom" json:"effectiveFrom"`
EffectiveTo *time.Time `bson:"effectiveTo,omitempty" json:"effectiveTo,omitempty"`
}

View File

@@ -0,0 +1,69 @@
package mongo
import (
"context"
"time"
"github.com/tech/sendico/billing/fees/storage"
"github.com/tech/sendico/billing/fees/storage/mongo/store"
"github.com/tech/sendico/pkg/db"
"github.com/tech/sendico/pkg/merrors"
"github.com/tech/sendico/pkg/mlogger"
"go.mongodb.org/mongo-driver/v2/mongo"
"go.uber.org/zap"
)
type Store struct {
logger mlogger.Logger
conn *db.MongoConnection
db *mongo.Database
plans storage.PlansStore
}
// New creates a repository backed by MongoDB for the billing fees service.
func New(logger mlogger.Logger, conn *db.MongoConnection) (*Store, error) {
if conn == nil {
return nil, merrors.InvalidArgument("mongo connection is nil")
}
client := conn.Client()
if client == nil {
return nil, merrors.Internal("mongo client not initialised")
}
database := conn.Database()
result := &Store{
logger: logger.Named("storage").Named("mongo"),
conn: conn,
db: database,
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := result.Ping(ctx); err != nil {
result.logger.Error("mongo ping failed during store init", zap.Error(err))
return nil, err
}
plansStore, err := store.NewPlans(result.logger, database)
if err != nil {
result.logger.Error("failed to initialise plans store", zap.Error(err))
return nil, err
}
result.plans = plansStore
result.logger.Info("Billing fees MongoDB storage initialised")
return result, nil
}
func (s *Store) Ping(ctx context.Context) error {
return s.conn.Ping(ctx)
}
func (s *Store) Plans() storage.PlansStore {
return s.plans
}
var _ storage.Repository = (*Store)(nil)

View File

@@ -0,0 +1,353 @@
package store
import (
"context"
"errors"
"fmt"
"sort"
"strings"
"time"
"github.com/tech/sendico/billing/fees/storage"
"github.com/tech/sendico/billing/fees/storage/model"
"github.com/tech/sendico/pkg/db/repository"
"github.com/tech/sendico/pkg/db/repository/builder"
ri "github.com/tech/sendico/pkg/db/repository/index"
dmath "github.com/tech/sendico/pkg/decimal"
"github.com/tech/sendico/pkg/merrors"
"github.com/tech/sendico/pkg/mlogger"
m "github.com/tech/sendico/pkg/model"
"github.com/tech/sendico/pkg/mservice"
"go.mongodb.org/mongo-driver/v2/bson"
"go.mongodb.org/mongo-driver/v2/mongo"
"go.uber.org/zap"
)
type plansStore struct {
logger mlogger.Logger
repo repository.Repository
}
// NewPlans constructs a Mongo-backed PlansStore.
func NewPlans(logger mlogger.Logger, db *mongo.Database) (storage.PlansStore, error) {
repo := repository.CreateMongoRepository(db, mservice.FeePlans)
// Index for organisation lookups.
orgIndex := &ri.Definition{
Keys: []ri.Key{
{Field: m.OrganizationRefField, Sort: ri.Asc},
{Field: "effectiveFrom", Sort: ri.Desc},
},
}
if err := repo.CreateIndex(orgIndex); err != nil {
logger.Error("failed to ensure fee plan organization index", zap.Error(err))
return nil, err
}
// Unique index for plan versions (per organisation + effectiveFrom).
uniqueIndex := &ri.Definition{
Keys: []ri.Key{
{Field: m.OrganizationRefField, Sort: ri.Asc},
{Field: "effectiveFrom", Sort: ri.Asc},
},
Unique: true,
}
if err := repo.CreateIndex(uniqueIndex); err != nil {
logger.Error("failed to ensure fee plan uniqueness index", zap.Error(err))
return nil, err
}
// Recommended index to speed up active-plan lookups (org/global + active + dates).
activeIndex := &ri.Definition{
Keys: []ri.Key{
{Field: m.OrganizationRefField, Sort: ri.Asc},
{Field: "active", Sort: ri.Asc},
{Field: "effectiveFrom", Sort: ri.Asc},
{Field: "effectiveTo", Sort: ri.Asc},
},
}
if err := repo.CreateIndex(activeIndex); err != nil {
logger.Warn("failed to ensure fee plan active index", zap.Error(err))
}
return &plansStore{
logger: logger.Named("plans"),
repo: repo,
}, nil
}
func (p *plansStore) Create(ctx context.Context, plan *model.FeePlan) error {
if err := validatePlan(plan); err != nil {
return err
}
if err := p.ensureNoOverlap(ctx, plan); err != nil {
return err
}
if err := p.repo.Insert(ctx, plan, nil); err != nil {
if errors.Is(err, merrors.ErrDataConflict) {
return storage.ErrDuplicateFeePlan
}
p.logger.Warn("failed to create fee plan", zap.Error(err))
return err
}
return nil
}
func (p *plansStore) Update(ctx context.Context, plan *model.FeePlan) error {
if plan == nil || plan.GetID() == nil || plan.GetID().IsZero() {
return merrors.InvalidArgument("plansStore: invalid fee plan reference")
}
if err := validatePlan(plan); err != nil {
return err
}
if err := p.ensureNoOverlap(ctx, plan); err != nil {
return err
}
if err := p.repo.Update(ctx, plan); err != nil {
p.logger.Warn("failed to update fee plan", zap.Error(err))
return err
}
return nil
}
func (p *plansStore) Get(ctx context.Context, planRef bson.ObjectID) (*model.FeePlan, error) {
if planRef.IsZero() {
return nil, merrors.InvalidArgument("plansStore: zero plan reference")
}
result := &model.FeePlan{}
if err := p.repo.Get(ctx, planRef, result); err != nil {
if errors.Is(err, merrors.ErrNoData) {
return nil, storage.ErrFeePlanNotFound
}
return nil, err
}
return result, nil
}
func (p *plansStore) GetActivePlan(ctx context.Context, orgRef bson.ObjectID, at time.Time) (*model.FeePlan, error) {
// Compatibility shim: prefer org plan, fall back to global; allow zero org to mean global.
if orgRef.IsZero() {
return p.FindActiveGlobalPlan(ctx, at)
}
plan, err := p.FindActiveOrgPlan(ctx, orgRef, at)
if err == nil {
return plan, nil
}
if errors.Is(err, storage.ErrFeePlanNotFound) {
return p.FindActiveGlobalPlan(ctx, at)
}
return nil, err
}
func (p *plansStore) FindActiveOrgPlan(ctx context.Context, orgRef bson.ObjectID, at time.Time) (*model.FeePlan, error) {
if orgRef.IsZero() {
return nil, merrors.InvalidArgument("plansStore: zero organization reference")
}
query := repository.Query().Filter(repository.OrgField(), orgRef)
return p.findActivePlan(ctx, query, at)
}
func (p *plansStore) FindActiveGlobalPlan(ctx context.Context, at time.Time) (*model.FeePlan, error) {
globalQuery := repository.Query().Or(
repository.Exists(repository.OrgField(), false),
repository.Query().Filter(repository.OrgField(), nil),
)
return p.findActivePlan(ctx, globalQuery, at)
}
var _ storage.PlansStore = (*plansStore)(nil)
func (p *plansStore) findActivePlan(ctx context.Context, orgQuery builder.Query, at time.Time) (*model.FeePlan, error) {
limit := int64(2)
query := orgQuery.
Filter(repository.Field("active"), true).
Comparison(repository.Field("effectiveFrom"), builder.Lte, at).
Sort(repository.Field("effectiveFrom"), false).
Limit(&limit)
query = query.And(
repository.Query().Or(
repository.Query().Filter(repository.Field("effectiveTo"), nil),
repository.Query().Comparison(repository.Field("effectiveTo"), builder.Gte, at),
),
)
var plans []*model.FeePlan
decoder := func(cursor *mongo.Cursor) error {
target := &model.FeePlan{}
if err := cursor.Decode(target); err != nil {
return err
}
plans = append(plans, target)
return nil
}
if err := p.repo.FindManyByFilter(ctx, query, decoder); err != nil {
if errors.Is(err, merrors.ErrNoData) {
return nil, storage.ErrFeePlanNotFound
}
return nil, err
}
if len(plans) == 0 {
return nil, storage.ErrFeePlanNotFound
}
if len(plans) > 1 {
return nil, storage.ErrConflictingFeePlans
}
return plans[0], nil
}
func validatePlan(plan *model.FeePlan) error {
if plan == nil {
return merrors.InvalidArgument("plansStore: nil fee plan")
}
if len(plan.Rules) == 0 {
return merrors.InvalidArgument("plansStore: fee plan must contain at least one rule")
}
if plan.Active && plan.EffectiveTo != nil && plan.EffectiveTo.Before(plan.EffectiveFrom) {
return merrors.InvalidArgument("plansStore: effectiveTo cannot be before effectiveFrom")
}
// Ensure unique priority per (trigger, appliesTo) combination.
seen := make(map[string]struct{})
for _, rule := range plan.Rules {
if strings.TrimSpace(rule.Percentage) != "" {
if _, err := dmath.RatFromString(rule.Percentage); err != nil {
return merrors.InvalidArgument("plansStore: invalid rule percentage")
}
}
if strings.TrimSpace(rule.FixedAmount) != "" {
if _, err := dmath.RatFromString(rule.FixedAmount); err != nil {
return merrors.InvalidArgument("plansStore: invalid rule fixed amount")
}
}
if strings.TrimSpace(rule.MinimumAmount) != "" {
if _, err := dmath.RatFromString(rule.MinimumAmount); err != nil {
return merrors.InvalidArgument("plansStore: invalid rule minimum amount")
}
}
if strings.TrimSpace(rule.MaximumAmount) != "" {
if _, err := dmath.RatFromString(rule.MaximumAmount); err != nil {
return merrors.InvalidArgument("plansStore: invalid rule maximum amount")
}
}
appliesKey := normalizeAppliesTo(rule.AppliesTo)
priorityKey := fmt.Sprintf("%s|%d|%s", rule.Trigger, rule.Priority, appliesKey)
if _, ok := seen[priorityKey]; ok {
return merrors.InvalidArgument("plansStore: duplicate priority for trigger/appliesTo")
}
seen[priorityKey] = struct{}{}
}
return nil
}
func normalizeAppliesTo(applies map[string]string) string {
if len(applies) == 0 {
return ""
}
keys := make([]string, 0, len(applies))
for k := range applies {
keys = append(keys, k)
}
sort.Strings(keys)
parts := make([]string, 0, len(keys))
for _, k := range keys {
parts = append(parts, k+"="+normalizeAppliesToValue(applies[k]))
}
return strings.Join(parts, ",")
}
func normalizeAppliesToValue(value string) string {
trimmed := strings.TrimSpace(value)
if trimmed == "" {
return ""
}
values := strings.Split(trimmed, ",")
seen := make(map[string]struct{}, len(values))
normalized := make([]string, 0, len(values))
hasWildcard := false
for _, value := range values {
value = strings.TrimSpace(value)
if value == "" {
continue
}
if value == "*" {
hasWildcard = true
continue
}
if _, ok := seen[value]; ok {
continue
}
seen[value] = struct{}{}
normalized = append(normalized, value)
}
if hasWildcard {
return "*"
}
if len(normalized) == 0 {
return ""
}
sort.Strings(normalized)
return strings.Join(normalized, ",")
}
func (p *plansStore) ensureNoOverlap(ctx context.Context, plan *model.FeePlan) error {
if plan == nil || !plan.Active {
return nil
}
orgQuery := repository.Query()
if plan.OrganizationRef.IsZero() {
orgQuery = repository.Query().Or(
repository.Exists(repository.OrgField(), false),
repository.Query().Filter(repository.OrgField(), nil),
)
} else {
orgQuery = repository.Query().Filter(repository.OrgField(), plan.OrganizationRef)
}
maxTime := time.Date(9999, 12, 31, 23, 59, 59, 0, time.UTC)
newFrom := plan.EffectiveFrom
newTo := maxTime
if plan.EffectiveTo != nil {
newTo = *plan.EffectiveTo
}
query := orgQuery.
Filter(repository.Field("active"), true).
Comparison(repository.Field("effectiveFrom"), builder.Lte, newTo).
And(repository.Query().Or(
repository.Query().Filter(repository.Field("effectiveTo"), nil),
repository.Query().Comparison(repository.Field("effectiveTo"), builder.Gte, newFrom),
))
if id := plan.GetID(); id != nil && !id.IsZero() {
query = query.And(repository.Query().Comparison(repository.IDField(), builder.Ne, *id))
}
limit := int64(1)
query = query.Limit(&limit)
var overlapFound bool
decoder := func(cursor *mongo.Cursor) error {
overlapFound = true
return nil
}
if err := p.repo.FindManyByFilter(ctx, query, decoder); err != nil {
if errors.Is(err, merrors.ErrNoData) {
return nil
}
return err
}
if overlapFound {
return storage.ErrConflictingFeePlans
}
return nil
}

View File

@@ -0,0 +1,39 @@
package storage
import (
"context"
"time"
"github.com/tech/sendico/billing/fees/storage/model"
"go.mongodb.org/mongo-driver/v2/bson"
)
type storageError string
func (e storageError) Error() string {
return string(e)
}
var (
// ErrFeePlanNotFound indicates that a requested fee plan does not exist.
ErrFeePlanNotFound = storageError("billing.fees.storage: fee plan not found")
// ErrDuplicateFeePlan indicates that a unique plan constraint was violated.
ErrDuplicateFeePlan = storageError("billing.fees.storage: duplicate fee plan")
// ErrConflictingFeePlans indicates multiple active plans matched a query.
ErrConflictingFeePlans = storageError("billing.fees.storage: conflicting fee plans")
)
// Repository defines the root storage contract for the fees service.
type Repository interface {
Ping(ctx context.Context) error
Plans() PlansStore
}
// PlansStore exposes persistence operations for fee plans.
type PlansStore interface {
Create(ctx context.Context, plan *model.FeePlan) error
Update(ctx context.Context, plan *model.FeePlan) error
Get(ctx context.Context, planRef bson.ObjectID) (*model.FeePlan, error)
// Legacy helper that now prefers an org plan and falls back to a global plan.
GetActivePlan(ctx context.Context, orgRef bson.ObjectID, at time.Time) (*model.FeePlan, error)
}

46
api/discovery/.air.toml Normal file
View File

@@ -0,0 +1,46 @@
root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"
[build]
args_bin = []
entrypoint = "./tmp/main"
cmd = "go build -o ./tmp/main ."
delay = 1000
exclude_dir = ["assets", "tmp", "vendor", "testdata"]
exclude_file = []
exclude_regex = ["_test.go", "_templ.go"]
exclude_unchanged = false
follow_symlink = false
full_bin = ""
include_dir = []
include_ext = ["go", "tpl", "tmpl", "html"]
include_file = []
kill_delay = "0s"
log = "build-errors.log"
poll = false
poll_interval = 0
post_cmd = []
pre_cmd = []
rerun = false
rerun_delay = 500
send_interrupt = false
stop_on_error = false
[color]
app = ""
build = "yellow"
main = "magenta"
runner = "green"
watcher = "cyan"
[log]
main_only = false
time = false
[misc]
clean_on_exit = false
[screen]
clear_on_rebuild = false
keep_scroll = true

4
api/discovery/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
internal/generated
.gocache
app
tmp

View File

@@ -0,0 +1,21 @@
runtime:
shutdown_timeout_seconds: 15
metrics:
address: ":9405"
messaging:
driver: NATS
settings:
url_env: NATS_URL
host_env: NATS_HOST
port_env: NATS_PORT
username_env: NATS_USER
password_env: NATS_PASSWORD
broker_name: Discovery Service
max_reconnects: 10
reconnect_wait: 5
buffer_size: 1024
registry:
kv_ttl_seconds: 3600

21
api/discovery/config.yml Normal file
View File

@@ -0,0 +1,21 @@
runtime:
shutdown_timeout_seconds: 15
metrics:
address: ":9405"
messaging:
driver: NATS
settings:
url_env: NATS_URL
host_env: NATS_HOST
port_env: NATS_PORT
username_env: NATS_USER
password_env: NATS_PASSWORD
broker_name: Discovery Service
max_reconnects: 10
reconnect_wait: 5
buffer_size: 1024
registry:
kv_ttl_seconds: 3600

49
api/discovery/go.mod Normal file
View File

@@ -0,0 +1,49 @@
module github.com/tech/sendico/discovery
go 1.25.6
replace github.com/tech/sendico/pkg => ../pkg
require (
github.com/go-chi/chi/v5 v5.2.4
github.com/prometheus/client_golang v1.23.2
github.com/tech/sendico/pkg v0.1.0
go.uber.org/zap v1.27.1
gopkg.in/yaml.v3 v3.0.1
)
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/bmatcuk/doublestar/v4 v4.10.0 // indirect
github.com/casbin/casbin/v2 v2.135.0 // indirect
github.com/casbin/govaluate v1.10.0 // indirect
github.com/casbin/mongodb-adapter/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/klauspost/compress v1.18.3 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nats-io/nats.go v1.48.0 // indirect
github.com/nats-io/nkeys v0.4.15 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.67.5 // indirect
github.com/prometheus/procfs v0.19.2 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.2.0 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
golang.org/x/crypto v0.47.0 // indirect
golang.org/x/net v0.49.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.40.0 // indirect
golang.org/x/text v0.33.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260202165425-ce8ad4cf556b // indirect
google.golang.org/grpc v1.78.0 // indirect
google.golang.org/protobuf v1.36.11 // indirect
)

221
api/discovery/go.sum Normal file
View File

@@ -0,0 +1,221 @@
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs=
github.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/casbin/casbin/v2 v2.135.0 h1:6BLkMQiGotYyS5yYeWgW19vxqugUlvHFkFiLnLR/bxk=
github.com/casbin/casbin/v2 v2.135.0/go.mod h1:FmcfntdXLTcYXv/hxgNntcRPqAbwOG9xsism0yXT+18=
github.com/casbin/govaluate v1.3.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A=
github.com/casbin/govaluate v1.10.0 h1:ffGw51/hYH3w3rZcxO/KcaUIDOLP84w7nsidMVgaDG0=
github.com/casbin/govaluate v1.10.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A=
github.com/casbin/mongodb-adapter/v4 v4.3.0 h1:yYXky9v1by6vj/0QK7OyHyd/xpz4vzh0lCi7JKrS4qQ=
github.com/casbin/mongodb-adapter/v4 v4.3.0/go.mod h1:bOTSYZUjX7I9E0ExEvgq46m3mcDNRII7g8iWjrM1BHE=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA=
github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI=
github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4=
github.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw=
github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 h1:mFWunSatvkQQDhpdyuFAYwyAan3hzCuma+Pz8sqvOfg=
github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo=
github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/nats-io/nats.go v1.48.0 h1:pSFyXApG+yWU/TgbKCjmm5K4wrHu86231/w84qRVR+U=
github.com/nats-io/nats.go v1.48.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
github.com/nats-io/nkeys v0.4.15 h1:JACV5jRVO9V856KOapQ7x+EY8Jo3qw1vJt/9Jpwzkk4=
github.com/nats-io/nkeys v0.4.15/go.mod h1:CpMchTXC9fxA5zrMo4KpySxNjiDVvr8ANOSZdiNfUrs=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/testcontainers/testcontainers-go v0.33.0 h1:zJS9PfXYT5O0ZFXM2xxXfk4J5UMw/kRiISng037Gxdw=
github.com/testcontainers/testcontainers-go v0.33.0/go.mod h1:W80YpTa8D5C3Yy16icheD01UTDu+LmXIA2Keo+jWtT8=
github.com/testcontainers/testcontainers-go/modules/mongodb v0.33.0 h1:iXVA84s5hKMS5gn01GWOYHE3ymy/2b+0YkpFeTxB2XY=
github.com/testcontainers/testcontainers-go/modules/mongodb v0.33.0/go.mod h1:R6tMjTojRiaoo89fh/hf7tOmfzohdqSU17R9DwSVSog=
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.2.0 h1:bYKF2AEwG5rqd1BumT4gAnvwU/M9nBp2pTSxeZw7Wvs=
github.com/xdg-go/scram v1.2.0/go.mod h1:3dlrS0iBaWKYVt2ZfA4cj48umJZ+cAEbR6/SjLA88I8=
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF3xaE=
go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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-20260202165425-ce8ad4cf556b h1:GZxXGdFaHX27ZSMHudWc4FokdD+xl8BC2UJm1OVIEzs=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260202165425-ce8ad4cf556b/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
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=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -0,0 +1,27 @@
package appversion
import (
"github.com/tech/sendico/pkg/version"
vf "github.com/tech/sendico/pkg/version/factory"
)
// Build information. Populated at build-time.
var (
Version string
Revision string
Branch string
BuildUser string
BuildDate string
)
func Create() version.Printer {
vi := version.Info{
Program: "Sendico Discovery Service",
Revision: Revision,
Branch: Branch,
BuildUser: BuildUser,
BuildDate: BuildDate,
Version: Version,
}
return vf.Create(&vi)
}

View File

@@ -0,0 +1,52 @@
package serverimp
import (
"os"
"strings"
msg "github.com/tech/sendico/pkg/messaging"
"github.com/tech/sendico/pkg/server/grpcapp"
"go.uber.org/zap"
"gopkg.in/yaml.v3"
)
const defaultMetricsAddress = ":9405"
type config struct {
Runtime *grpcapp.RuntimeConfig `yaml:"runtime"`
Messaging *msg.Config `yaml:"messaging"`
Metrics *metricsConfig `yaml:"metrics"`
Registry *registryConfig `yaml:"registry"`
}
type metricsConfig struct {
Address string `yaml:"address"`
}
type registryConfig struct {
KVTTLSeconds *int `yaml:"kv_ttl_seconds"`
}
func (i *Imp) loadConfig() (*config, error) {
data, err := os.ReadFile(i.file)
if err != nil {
i.logger.Error("Could not read configuration file", zap.String("config_file", i.file), zap.Error(err))
return nil, err
}
cfg := &config{}
if err := yaml.Unmarshal(data, cfg); err != nil {
i.logger.Error("Failed to parse configuration", zap.Error(err))
return nil, err
}
if cfg.Runtime == nil {
cfg.Runtime = &grpcapp.RuntimeConfig{ShutdownTimeoutSeconds: 15}
}
if cfg.Metrics != nil && strings.TrimSpace(cfg.Metrics.Address) == "" {
cfg.Metrics.Address = defaultMetricsAddress
}
return cfg, nil
}

View File

@@ -0,0 +1,69 @@
package serverimp
import (
"time"
"github.com/tech/sendico/discovery/internal/appversion"
"github.com/tech/sendico/pkg/discovery"
"github.com/tech/sendico/pkg/merrors"
msg "github.com/tech/sendico/pkg/messaging"
msgproducer "github.com/tech/sendico/pkg/messaging/producer"
"github.com/tech/sendico/pkg/mservice"
"go.uber.org/zap"
)
func (i *Imp) startDiscovery(cfg *config) error {
if cfg == nil || cfg.Messaging == nil || cfg.Messaging.Driver == "" {
return merrors.InvalidArgument("discovery service: messaging configuration is required", "messaging")
}
broker, err := msg.CreateMessagingBroker(i.logger.Named("discovery_bus"), cfg.Messaging)
if err != nil {
return err
}
i.logger.Info("Discovery messaging broker ready", zap.String("messaging_driver", string(cfg.Messaging.Driver)))
producer := msgproducer.NewProducer(i.logger.Named("discovery_producer"), broker)
registry := discovery.NewRegistry()
var registryOpts []discovery.RegistryOption
if cfg.Registry != nil && cfg.Registry.KVTTLSeconds != nil {
ttlSeconds := *cfg.Registry.KVTTLSeconds
if ttlSeconds < 0 {
i.logger.Warn("Discovery registry TTL is negative, disabling TTL", zap.Int("ttl_seconds", ttlSeconds))
ttlSeconds = 0
}
registryOpts = append(registryOpts, discovery.WithRegistryKVTTL(time.Duration(ttlSeconds)*time.Second))
}
svc, err := discovery.NewRegistryService(i.logger, broker, producer, registry, string(mservice.Discovery), registryOpts...)
if err != nil {
return err
}
svc.Start()
i.registrySvc = svc
announce := discovery.Announcement{
Service: "DISCOVERY",
InstanceID: discovery.InstanceID(),
Operations: []string{"discovery.lookup"},
Version: appversion.Create().Short(),
}
i.announcer = discovery.NewAnnouncer(i.logger, producer, string(mservice.Discovery), announce)
i.announcer.Start()
i.logger.Info("Discovery registry service started", zap.String("messaging_driver", string(cfg.Messaging.Driver)))
return nil
}
func (i *Imp) stopDiscovery() {
if i == nil {
return
}
if i.announcer != nil {
i.announcer.Stop()
i.announcer = nil
}
if i.registrySvc != nil {
i.registrySvc.Stop()
i.registrySvc = nil
}
}

View File

@@ -0,0 +1,88 @@
package serverimp
import (
"context"
"errors"
"net"
"net/http"
"strings"
"time"
"github.com/go-chi/chi/v5"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/tech/sendico/pkg/api/routers"
"github.com/tech/sendico/pkg/api/routers/health"
"go.uber.org/zap"
)
func (i *Imp) startMetrics(cfg *metricsConfig) {
if i == nil {
return
}
address := ""
if cfg != nil {
address = strings.TrimSpace(cfg.Address)
}
if address == "" {
i.logger.Info("Metrics endpoint disabled")
return
}
listener, err := net.Listen("tcp", address)
if err != nil {
i.logger.Error("Failed to bind metrics listener", zap.String("address", address), zap.Error(err))
return
}
router := chi.NewRouter()
router.Handle("/metrics", promhttp.Handler())
var healthRouter routers.Health
if hr, err := routers.NewHealthRouter(i.logger.Named("metrics"), router, ""); err != nil {
i.logger.Warn("Failed to initialise health router", zap.Error(err))
} else {
hr.SetStatus(health.SSStarting)
healthRouter = hr
}
i.metricsHealth = healthRouter
i.metricsSrv = &http.Server{
Addr: address,
Handler: router,
ReadHeaderTimeout: 5 * time.Second,
}
go func() {
i.logger.Info("Prometheus endpoint listening", zap.String("address", address))
if err := i.metricsSrv.Serve(listener); err != nil && !errors.Is(err, http.ErrServerClosed) {
i.logger.Error("Prometheus endpoint stopped unexpectedly", zap.Error(err))
if healthRouter != nil {
healthRouter.SetStatus(health.SSTerminating)
}
}
}()
}
func (i *Imp) shutdownMetrics(ctx context.Context) {
if i.metricsHealth != nil {
i.metricsHealth.SetStatus(health.SSTerminating)
i.metricsHealth.Finish()
i.metricsHealth = nil
}
if i.metricsSrv == nil {
return
}
if err := i.metricsSrv.Shutdown(ctx); err != nil && !errors.Is(err, http.ErrServerClosed) {
i.logger.Warn("Failed to stop metrics server", zap.Error(err))
} else {
i.logger.Info("Metrics server stopped")
}
i.metricsSrv = nil
}
func (i *Imp) setMetricsStatus(status health.ServiceStatus) {
if i == nil || i.metricsHealth == nil {
return
}
i.metricsHealth.SetStatus(status)
}

View File

@@ -0,0 +1,112 @@
package serverimp
import (
"context"
"strings"
"time"
"github.com/tech/sendico/pkg/api/routers/health"
"github.com/tech/sendico/pkg/mlogger"
"go.uber.org/zap"
)
func Create(logger mlogger.Logger, file string, debug bool) (*Imp, error) {
return &Imp{
logger: logger.Named("server"),
file: file,
debug: debug,
}, nil
}
func (i *Imp) Start() error {
i.initStopChannels()
defer i.closeDone()
i.logger.Info("Starting discovery service", zap.String("config_file", i.file), zap.Bool("debug", i.debug))
cfg, err := i.loadConfig()
if err != nil {
return err
}
i.config = cfg
messagingDriver := "none"
if cfg.Messaging != nil {
messagingDriver = string(cfg.Messaging.Driver)
}
metricsAddress := ""
if cfg.Metrics != nil {
metricsAddress = strings.TrimSpace(cfg.Metrics.Address)
}
if metricsAddress == "" {
metricsAddress = "disabled"
}
i.logger.Info("Discovery config loaded", zap.String("messaging_driver", messagingDriver), zap.String("metrics_address", metricsAddress))
i.startMetrics(cfg.Metrics)
if err := i.startDiscovery(cfg); err != nil {
i.stopDiscovery()
i.setMetricsStatus(health.SSTerminating)
ctx, cancel := context.WithTimeout(context.Background(), i.shutdownTimeout())
i.shutdownMetrics(ctx)
cancel()
return err
}
i.setMetricsStatus(health.SSRunning)
i.logger.Info("Discovery service ready", zap.String("messaging_driver", messagingDriver))
<-i.stopCh
i.logger.Info("Discovery service stop signal received")
return nil
}
func (i *Imp) Shutdown() {
timeout := i.shutdownTimeout()
i.logger.Info("Stopping discovery service", zap.Duration("timeout", timeout))
i.stopDiscovery()
i.signalStop()
if i.doneCh != nil {
<-i.doneCh
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
i.shutdownMetrics(ctx)
cancel()
i.logger.Info("Discovery service stopped")
}
func (i *Imp) initStopChannels() {
if i.stopCh == nil {
i.stopCh = make(chan struct{})
}
if i.doneCh == nil {
i.doneCh = make(chan struct{})
}
}
func (i *Imp) signalStop() {
i.stopOnce.Do(func() {
if i.stopCh != nil {
close(i.stopCh)
}
})
}
func (i *Imp) closeDone() {
i.doneOnce.Do(func() {
if i.doneCh != nil {
close(i.doneCh)
}
})
}
func (i *Imp) shutdownTimeout() time.Duration {
if i.config != nil && i.config.Runtime != nil {
return i.config.Runtime.ShutdownTimeout()
}
return 15 * time.Second
}

View File

@@ -0,0 +1,28 @@
package serverimp
import (
"net/http"
"sync"
"github.com/tech/sendico/pkg/api/routers"
"github.com/tech/sendico/pkg/discovery"
"github.com/tech/sendico/pkg/mlogger"
)
type Imp struct {
logger mlogger.Logger
file string
debug bool
config *config
registrySvc *discovery.RegistryService
announcer *discovery.Announcer
metricsSrv *http.Server
metricsHealth routers.Health
stopOnce sync.Once
doneOnce sync.Once
stopCh chan struct{}
doneCh chan struct{}
}

View File

@@ -0,0 +1,11 @@
package server
import (
serverimp "github.com/tech/sendico/discovery/internal/server/internal"
"github.com/tech/sendico/pkg/mlogger"
"github.com/tech/sendico/pkg/server"
)
func Create(logger mlogger.Logger, file string, debug bool) (server.Application, error) {
return serverimp.Create(logger, file, debug)
}

17
api/discovery/main.go Normal file
View File

@@ -0,0 +1,17 @@
package main
import (
"github.com/tech/sendico/discovery/internal/appversion"
si "github.com/tech/sendico/discovery/internal/server"
"github.com/tech/sendico/pkg/mlogger"
"github.com/tech/sendico/pkg/server"
smain "github.com/tech/sendico/pkg/server/main"
)
func factory(logger mlogger.Logger, file string, debug bool) (server.Application, error) {
return si.Create(logger, file, debug)
}
func main() {
smain.RunServer("main", appversion.Create(), factory)
}

46
api/fx/ingestor/.air.toml Normal file
View File

@@ -0,0 +1,46 @@
root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"
[build]
args_bin = []
entrypoint = "./tmp/main"
cmd = "go build -o ./tmp/main ."
delay = 1000
exclude_dir = ["assets", "tmp", "vendor", "testdata"]
exclude_file = []
exclude_regex = ["_test.go", "_templ.go"]
exclude_unchanged = false
follow_symlink = false
full_bin = ""
include_dir = []
include_ext = ["go", "tpl", "tmpl", "html"]
include_file = []
kill_delay = "0s"
log = "build-errors.log"
poll = false
poll_interval = 0
post_cmd = []
pre_cmd = []
rerun = false
rerun_delay = 500
send_interrupt = false
stop_on_error = false
[color]
app = ""
build = "yellow"
main = "magenta"
runner = "green"
watcher = "cyan"
[log]
main_only = false
time = false
[misc]
clean_on_exit = false
[screen]
clear_on_rebuild = false
keep_scroll = true

4
api/fx/ingestor/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
internal/generated
.gocache
/app
tmp

View File

@@ -0,0 +1,74 @@
poll_interval_seconds: 30
market:
sources:
- driver: BINANCE
settings:
base_url: "https://api.binance.com"
- driver: COINGECKO
settings:
base_url: "https://api.coingecko.com/api/v3"
- driver: CBR
settings:
base_url: "https://www.cbr.ru"
user_agent: "Mozilla/5.0 (compatible; SendicoFX/1.0; +https://app.sendico.io)"
accept_header: "application/xml,text/xml;q=0.9,*/*;q=0.8"
pairs:
BINANCE:
- base: "USDT"
quote: "EUR"
symbol: "EURUSDT"
invert: true
- base: "USD"
quote: "USDT"
symbol: "USDTUSD"
invert: true
- base: "UAH"
quote: "USDT"
symbol: "USDTUAH"
invert: true
- base: "USDC"
quote: "EUR"
symbol: "EURUSDC"
invert: true
COINGECKO:
- base: "USDT"
quote: "RUB"
symbol: "tether:rub"
CBR:
- base: "USD"
quote: "RUB"
symbol: "USD"
provider: "cbr"
- base: "EUR"
quote: "RUB"
symbol: "EUR"
provider: "cbr"
metrics:
enabled: true
address: ":9102"
messaging:
driver: NATS
settings:
url_env: NATS_URL
host_env: NATS_HOST
port_env: NATS_PORT
username_env: NATS_USER
password_env: NATS_PASSWORD
broker_name: FX Ingestor
max_reconnects: 10
reconnect_wait: 5
buffer_size: 1024
database:
driver: mongodb
settings:
host_env: FX_MONGO_HOST
port_env: FX_MONGO_PORT
database_env: FX_MONGO_DATABASE
user_env: FX_MONGO_USER
password_env: FX_MONGO_PASSWORD
auth_source_env: FX_MONGO_AUTH_SOURCE
replica_set_env: FX_MONGO_REPLICA_SET

View File

@@ -0,0 +1,74 @@
poll_interval_seconds: 30
market:
sources:
- driver: BINANCE
settings:
base_url: "https://api.binance.com"
- driver: COINGECKO
settings:
base_url: "https://api.coingecko.com/api/v3"
- driver: CBR
settings:
base_url: "https://www.cbr.ru"
user_agent: "Mozilla/5.0 (compatible; SendicoFX/1.0; +https://app.sendico.io)"
accept_header: "application/xml,text/xml;q=0.9,*/*;q=0.8"
pairs:
BINANCE:
- base: "USDT"
quote: "EUR"
symbol: "EURUSDT"
invert: true
- base: "USD"
quote: "USDT"
symbol: "USDTUSD"
invert: true
- base: "UAH"
quote: "USDT"
symbol: "USDTUAH"
invert: true
- base: "USDC"
quote: "EUR"
symbol: "EURUSDC"
invert: true
COINGECKO:
- base: "USDT"
quote: "RUB"
symbol: "tether:rub"
CBR:
- base: "USD"
quote: "RUB"
symbol: "USD"
provider: "cbr"
- base: "EUR"
quote: "RUB"
symbol: "EUR"
provider: "cbr"
metrics:
enabled: true
address: ":9102"
messaging:
driver: NATS
settings:
url_env: NATS_URL
host_env: NATS_HOST
port_env: NATS_PORT
username_env: NATS_USER
password_env: NATS_PASSWORD
broker_name: FX Ingestor
max_reconnects: 10
reconnect_wait: 5
buffer_size: 1024
database:
driver: mongodb
settings:
host_env: FX_MONGO_HOST
port_env: FX_MONGO_PORT
database_env: FX_MONGO_DATABASE
user_env: FX_MONGO_USER
password_env: FX_MONGO_PASSWORD
auth_source_env: FX_MONGO_AUTH_SOURCE
replica_set_env: FX_MONGO_REPLICA_SET

1
api/fx/ingestor/env/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.env.api

53
api/fx/ingestor/go.mod Normal file
View File

@@ -0,0 +1,53 @@
module github.com/tech/sendico/fx/ingestor
go 1.25.6
replace github.com/tech/sendico/pkg => ../../pkg
replace github.com/tech/sendico/fx/storage => ../storage
require (
github.com/go-chi/chi/v5 v5.2.4
github.com/google/go-cmp v0.7.0
github.com/prometheus/client_golang v1.23.2
github.com/tech/sendico/fx/storage v0.0.0
github.com/tech/sendico/pkg v0.1.0
go.uber.org/zap v1.27.1
golang.org/x/net v0.49.0
gopkg.in/yaml.v3 v3.0.1
)
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/bmatcuk/doublestar/v4 v4.10.0 // indirect
github.com/casbin/casbin/v2 v2.135.0 // indirect
github.com/casbin/govaluate v1.10.0 // indirect
github.com/casbin/mongodb-adapter/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/klauspost/compress v1.18.3 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nats-io/nats.go v1.48.0 // indirect
github.com/nats-io/nkeys v0.4.15 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.67.5 // indirect
github.com/prometheus/procfs v0.19.2 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.2.0 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
golang.org/x/crypto v0.47.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.40.0 // indirect
golang.org/x/text v0.33.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260202165425-ce8ad4cf556b // indirect
google.golang.org/grpc v1.78.0 // indirect
google.golang.org/protobuf v1.36.11 // indirect
)

221
api/fx/ingestor/go.sum Normal file
View File

@@ -0,0 +1,221 @@
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs=
github.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/casbin/casbin/v2 v2.135.0 h1:6BLkMQiGotYyS5yYeWgW19vxqugUlvHFkFiLnLR/bxk=
github.com/casbin/casbin/v2 v2.135.0/go.mod h1:FmcfntdXLTcYXv/hxgNntcRPqAbwOG9xsism0yXT+18=
github.com/casbin/govaluate v1.3.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A=
github.com/casbin/govaluate v1.10.0 h1:ffGw51/hYH3w3rZcxO/KcaUIDOLP84w7nsidMVgaDG0=
github.com/casbin/govaluate v1.10.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A=
github.com/casbin/mongodb-adapter/v4 v4.3.0 h1:yYXky9v1by6vj/0QK7OyHyd/xpz4vzh0lCi7JKrS4qQ=
github.com/casbin/mongodb-adapter/v4 v4.3.0/go.mod h1:bOTSYZUjX7I9E0ExEvgq46m3mcDNRII7g8iWjrM1BHE=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA=
github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI=
github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4=
github.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw=
github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 h1:mFWunSatvkQQDhpdyuFAYwyAan3hzCuma+Pz8sqvOfg=
github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo=
github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/nats-io/nats.go v1.48.0 h1:pSFyXApG+yWU/TgbKCjmm5K4wrHu86231/w84qRVR+U=
github.com/nats-io/nats.go v1.48.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
github.com/nats-io/nkeys v0.4.15 h1:JACV5jRVO9V856KOapQ7x+EY8Jo3qw1vJt/9Jpwzkk4=
github.com/nats-io/nkeys v0.4.15/go.mod h1:CpMchTXC9fxA5zrMo4KpySxNjiDVvr8ANOSZdiNfUrs=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/testcontainers/testcontainers-go v0.33.0 h1:zJS9PfXYT5O0ZFXM2xxXfk4J5UMw/kRiISng037Gxdw=
github.com/testcontainers/testcontainers-go v0.33.0/go.mod h1:W80YpTa8D5C3Yy16icheD01UTDu+LmXIA2Keo+jWtT8=
github.com/testcontainers/testcontainers-go/modules/mongodb v0.33.0 h1:iXVA84s5hKMS5gn01GWOYHE3ymy/2b+0YkpFeTxB2XY=
github.com/testcontainers/testcontainers-go/modules/mongodb v0.33.0/go.mod h1:R6tMjTojRiaoo89fh/hf7tOmfzohdqSU17R9DwSVSog=
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.2.0 h1:bYKF2AEwG5rqd1BumT4gAnvwU/M9nBp2pTSxeZw7Wvs=
github.com/xdg-go/scram v1.2.0/go.mod h1:3dlrS0iBaWKYVt2ZfA4cj48umJZ+cAEbR6/SjLA88I8=
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF3xaE=
go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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-20260202165425-ce8ad4cf556b h1:GZxXGdFaHX27ZSMHudWc4FokdD+xl8BC2UJm1OVIEzs=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260202165425-ce8ad4cf556b/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
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=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -0,0 +1,103 @@
package app
import (
"context"
"errors"
"strings"
"github.com/tech/sendico/fx/ingestor/internal/appversion"
"github.com/tech/sendico/fx/ingestor/internal/config"
"github.com/tech/sendico/fx/ingestor/internal/ingestor"
"github.com/tech/sendico/fx/ingestor/internal/metrics"
mongostorage "github.com/tech/sendico/fx/storage/mongo"
"github.com/tech/sendico/pkg/api/routers/health"
"github.com/tech/sendico/pkg/db"
"github.com/tech/sendico/pkg/discovery"
"github.com/tech/sendico/pkg/merrors"
msg "github.com/tech/sendico/pkg/messaging"
msgproducer "github.com/tech/sendico/pkg/messaging/producer"
"github.com/tech/sendico/pkg/mlogger"
"go.uber.org/zap"
)
const DefaultConfigPath = "config.yml"
type App struct {
logger mlogger.Logger
cfg *config.Config
}
func New(logger mlogger.Logger, cfgPath string) (*App, error) {
if logger == nil {
return nil, merrors.InvalidArgument("app: logger is nil")
}
path := strings.TrimSpace(cfgPath)
if path == "" {
path = DefaultConfigPath
}
cfg, err := config.Load(path)
if err != nil {
return nil, err
}
return &App{
logger: logger,
cfg: cfg,
}, nil
}
func (a *App) Run(ctx context.Context) error {
metricsSrv, err := metrics.NewServer(a.logger, a.cfg.MetricsConfig())
if err != nil {
return err
}
a.logger.Debug("Metrics server initialised")
defer metricsSrv.Close(context.Background())
conn, err := db.ConnectMongo(a.logger, a.cfg.Database)
if err != nil {
return err
}
defer conn.Disconnect(context.Background())
a.logger.Debug("MongoDB connection established")
repo, err := mongostorage.New(a.logger, conn)
if err != nil {
return err
}
a.logger.Debug("Storage repository initialised")
service, err := ingestor.New(a.logger, a.cfg, repo)
if err != nil {
return err
}
var announcer *discovery.Announcer
if cfg := a.cfg.Messaging; cfg != nil && cfg.Driver != "" {
broker, err := msg.CreateMessagingBroker(a.logger.Named("discovery_bus"), cfg)
if err != nil {
a.logger.Warn("Failed to initialize discovery broker", zap.Error(err))
} else {
producer := msgproducer.NewProducer(a.logger.Named("discovery_producer"), broker)
announce := discovery.Announcement{
Service: "FX_INGESTOR",
Operations: []string{"fx.ingest"},
Version: appversion.Create().Short(),
}
announcer = discovery.NewAnnouncer(a.logger, producer, "fx_ingestor", announce)
announcer.Start()
defer announcer.Stop()
}
}
a.logger.Info("Starting FX ingestor service", zap.String("version", appversion.Create().Info()))
metricsSrv.SetStatus(health.SSRunning)
if err := service.Run(ctx); err != nil {
if !errors.Is(err, context.Canceled) { // ignore termination reques error
a.logger.Error("Ingestor service exited with error", zap.Error(err))
}
return err
}
a.logger.Info("Ingestor service stopped")
return nil
}

View File

@@ -0,0 +1,27 @@
package appversion
import (
"github.com/tech/sendico/pkg/version"
vf "github.com/tech/sendico/pkg/version/factory"
)
// Build information. Populated at build-time.
var (
Version string
Revision string
Branch string
BuildUser string
BuildDate string
)
func Create() version.Printer {
vi := version.Info{
Program: "Sendico FX Ingestor Service",
Revision: Revision,
Branch: Branch,
BuildUser: BuildUser,
BuildDate: BuildDate,
Version: Version,
}
return vf.Create(&vi)
}

View File

@@ -0,0 +1,149 @@
package config
import (
"os"
"strings"
"time"
mmodel "github.com/tech/sendico/fx/ingestor/internal/model"
"github.com/tech/sendico/pkg/db"
"github.com/tech/sendico/pkg/merrors"
"github.com/tech/sendico/pkg/messaging"
"gopkg.in/yaml.v3"
)
const defaultPollInterval = 30 * time.Second
type Config struct {
PollIntervalSeconds int `yaml:"poll_interval_seconds"`
Market MarketConfig `yaml:"market"`
Database *db.Config `yaml:"database"`
Metrics *MetricsConfig `yaml:"metrics"`
Messaging *messaging.Config `yaml:"messaging"`
pairs []Pair
pairsBySource map[mmodel.Driver][]PairConfig
}
func Load(path string) (*Config, error) {
if path == "" {
return nil, merrors.InvalidArgument("config: path is empty")
}
data, err := os.ReadFile(path)
if err != nil {
return nil, merrors.InternalWrap(err, "config: failed to read file")
}
cfg := &Config{}
if err := yaml.Unmarshal(data, cfg); err != nil {
return nil, merrors.InternalWrap(err, "config: failed to parse yaml")
}
if len(cfg.Market.Sources) == 0 {
return nil, merrors.InvalidArgument("config: no market sources configured")
}
sourceSet := make(map[mmodel.Driver]struct{}, len(cfg.Market.Sources))
for idx := range cfg.Market.Sources {
src := &cfg.Market.Sources[idx]
if src.Driver.IsEmpty() {
return nil, merrors.InvalidArgument("config: market source driver is empty")
}
sourceSet[src.Driver] = struct{}{}
}
if len(cfg.Market.Pairs) == 0 {
return nil, merrors.InvalidArgument("config: no pairs configured")
}
normalizedPairs := make(map[string][]PairConfig, len(cfg.Market.Pairs))
pairsBySource := make(map[mmodel.Driver][]PairConfig, len(cfg.Market.Pairs))
var flattened []Pair
for rawSource, pairList := range cfg.Market.Pairs {
driver := mmodel.Driver(rawSource)
if driver.IsEmpty() {
return nil, merrors.InvalidArgument("config: pair source is empty")
}
if _, ok := sourceSet[driver]; !ok {
return nil, merrors.InvalidArgument("config: pair references unknown source: "+driver.String(), "pairs."+driver.String())
}
processed := make([]PairConfig, len(pairList))
for idx := range pairList {
pair := pairList[idx]
pair.Base = strings.ToUpper(strings.TrimSpace(pair.Base))
pair.Quote = strings.ToUpper(strings.TrimSpace(pair.Quote))
pair.Symbol = strings.TrimSpace(pair.Symbol)
if pair.Base == "" || pair.Quote == "" || pair.Symbol == "" {
return nil, merrors.InvalidArgument("config: pair entries must define base, quote, and symbol", "pairs."+driver.String())
}
if strings.TrimSpace(pair.Provider) == "" {
pair.Provider = strings.ToLower(driver.String())
}
processed[idx] = pair
flattened = append(flattened, Pair{
PairConfig: pair,
Source: driver,
})
}
pairsBySource[driver] = processed
normalizedPairs[driver.String()] = processed
}
cfg.Market.Pairs = normalizedPairs
cfg.pairsBySource = pairsBySource
cfg.pairs = flattened
if cfg.Database == nil {
return nil, merrors.InvalidArgument("config: database configuration is required")
}
if cfg.Metrics != nil && cfg.Metrics.Enabled {
cfg.Metrics.Address = strings.TrimSpace(cfg.Metrics.Address)
if cfg.Metrics.Address == "" {
cfg.Metrics.Address = ":9102"
}
}
return cfg, nil
}
func (c *Config) PollInterval() time.Duration {
if c == nil {
return defaultPollInterval
}
if c.PollIntervalSeconds <= 0 {
return defaultPollInterval
}
return time.Duration(c.PollIntervalSeconds) * time.Second
}
func (c *Config) Pairs() []Pair {
if c == nil {
return nil
}
out := make([]Pair, len(c.pairs))
copy(out, c.pairs)
return out
}
func (c *Config) PairsBySource() map[mmodel.Driver][]PairConfig {
if c == nil {
return nil
}
out := make(map[mmodel.Driver][]PairConfig, len(c.pairsBySource))
for driver, pairs := range c.pairsBySource {
cp := make([]PairConfig, len(pairs))
copy(cp, pairs)
out[driver] = cp
}
return out
}
func (c *Config) MetricsConfig() *MetricsConfig {
if c == nil || c.Metrics == nil {
return nil
}
cp := *c.Metrics
return &cp
}

Some files were not shown because too many files have changed in this diff Show More