# Sendico [![Build Status](https://ci.sendico.io/api/badges/1/status.svg?branch=main)](https://ci.sendico.io/repos/1)


Financial services platform providing payment orchestration, ledger accounting, FX conversion, and multi-rail payment processing.

## Architecture

- **Backend**: Go microservices with gRPC inter-service communication
- **Frontend**: Flutter/Dart web application
- **Infrastructure**: Woodpecker CI/CD, Docker, MongoDB, NATS, Vault

## Services

| Service | Path | Description |
|---------|------|-------------|
| Discovery | `api/discovery/` | Service registry |
| Ledger | `api/ledger/` | Double-entry accounting |
| Orchestrator | `api/payments/orchestrator/` | Payment orchestration |
| Quotation | `api/payments/quotation/` | Payment quotation |
| Payment Methods | `api/payments/methods/` | Payment methods |
| Billing Fees | `api/billing/fees/` | Fee calculation |
| Billing Documents | `api/billing/documents/` | Billing documents |
| FX Oracle | `api/fx/oracle/` | FX quote provider |
| FX Ingestor | `api/fx/ingestor/` | FX rate ingestion |
| Gateway Chain | `api/gateway/chain/` | EVM blockchain gateway |
| Gateway TRON | `api/gateway/tron/` | TRON blockchain gateway |
| Gateway Aurora | `api/gateway/aurora/` | Card payouts simulator |
| Gateway ChimeraSettle | `api/gateway/chsettle/` | Dummy settlement simulator (fast/slow/success/fail/stuck) |
| Gateway MNTX | `api/gateway/mntx/` | Card payouts |
| Gateway TGSettle (legacy) | `api/gateway/tgsettle/` | Legacy Telegram settlement gateway (not used in dev compose) |
| Notification | `api/notification/` | Notifications |
| BFF | `api/edge/bff/` | Backend for frontend |
| Callbacks | `api/edge/callbacks/` | Webhook callbacks delivery |
| Frontend | `frontend/pweb/` | Flutter web UI |

Gateway note: current dev compose workflows (`make services-up`, `make build-gateways`) use (`chain`, `tron`, `aurora`, `chsettle`). ChimeraSettle is the settlement simulator for test flows; it supports deterministic behavior routing via explicit scenario override and amount buckets. TGSettle remains in-repo as legacy code and is not started by default in dev compose.

## Prerequisites

- Docker with Docker Compose plugin
- GNU Make
- Go toolchain
- Dart SDK
- Flutter SDK

## Development

Development uses Docker Compose via the Makefile. Run `make help` for all available commands.

### Quick Start

```bash
make init       # First-time setup (generates keys, .env.dev, builds images)
make up         # Start all services
make vault-init # Initialize Vault (if needed)
```

### Common Commands

```bash
make build                # Build all service images
make up                   # Start all services
make down                 # Stop all services
make restart              # Restart all services
make status               # Show service status
make logs                 # View all logs
make logs SERVICE=dev-ledger  # View logs for a specific service
make rebuild SERVICE=dev-ledger # Rebuild and restart a specific service
make list-services        # List all services and ports
make health               # Check service health
make clean                # Remove all containers and volumes
```

### Selective Start

```bash
make infra-up      # Start infrastructure only (MongoDB, NATS, Vault)
make services-up   # Start application services only (assumes infra is running)
make backend-up    # Start backend services only (no infrastructure/frontend changes)
make backend-down  # Stop backend services only
make backend-rebuild # Rebuild and restart backend services only
make list-services # Show service names, ports, and descriptions
```

### Build Groups

```bash
make build-core       # discovery, ledger, fees, documents
make build-fx         # oracle, ingestor
make build-payments   # orchestrator, quotation, methods
make build-gateways   # chain, tron, aurora, chsettle
make build-backend    # notification, callbacks, bff
make build-frontend   # Flutter web UI
```

### Code Generation

```bash
make generate            # Generate all code (protobuf + Flutter)
make generate-backend    # Generate protobuf code only
make generate-frontend   # Generate Flutter code only (build_runner)
make proto               # Alias for generate-backend
```

### Testing

```bash
make test           # Run all tests (backend + frontend)
make test-backend   # Run Go backend tests only
make test-frontend  # Run Flutter tests only
```

## Release Flow

- Pushes to `main` build and deploy changed application services to the dev server.
- Tags matching `v*` trigger a full production rebuild and deployment from that exact tagged revision.
- Infrastructure workflows for `db`, `nats`, and the dev `vault` remain separately controlled via `[infra]`.

First-time dev bootstrap:

```bash
# merge a PR whose commit message includes [infra]
# this deploys dev db, nats, and dev vault
# after infra is green, merge normal app changes to main
```

Dev secret source:

- After the dev Vault bootstrap runs, dev build/deploy secrets are read from the dev Vault on the dev host.
- The dev SSH deploy key remains an external bootstrap secret because CI needs it before it can reach the dev host.

Recommended release preparation:

```bash
./ci/scripts/common/release.sh
# push your branch and open a PR
# merge the PR to main
git checkout main && git pull
# verify the dev deployment from main
./ci/scripts/common/tag_release.sh
git push origin v$(cat version)
```

Manual production release from an already-prepared commit:

```bash
git tag -a v1.4.0 <commit-sha>
git push origin v1.4.0
```

### Backend CI Bypass Tags

Backend Woodpecker module pipelines now run both lint and tests before image build/deploy.
If you intentionally need to bypass checks for a specific commit, include one of these tags in the commit message:

```text
[skip-lint:<service>]       # Skip lint for one backend service pipeline
[skip-lint]                 # Skip lint for all backend service pipelines
[skip-tests:<service>]      # Skip tests for one backend service pipeline
[skip-tests]                # Skip tests for all backend service pipelines
[skip-autotests:<service>]  # Alias for skip-tests:<service>
[skip-autotests]            # Alias for skip-tests
[skip-checks:<service>]     # Skip both lint and tests for one backend service pipeline
[skip-checks]               # Skip both lint and tests for all backend service pipelines
```

`<service>` must match the backend pipeline key used by CI:
`bff`, `callbacks`, `billing_documents`, `billing_fees`, `discovery`, `fx_ingestor`, `fx_oracle`, `gateway_chain`, `gateway_mntx`, `gateway_tgsettle`, `gateway_tron`, `ledger`, `notification`, `payments_methods`, `payments_orchestrator`, `payments_quotation`.

### Update Dependencies

```bash
make update            # Update all Go and Flutter dependencies
make update-backend    # Update Go dependencies only
make update-frontend   # Update Flutter dependencies only
```

### Callbacks Secret References

Callbacks (`api/edge/callbacks`) supports three secret reference formats:

- `env:MY_SECRET_ENV` to read from environment variables.
- `vault:some/path#field` to read a field from Vault KV v2.
- `some/path#field` to read from Vault KV v2 when `secrets.vault` is configured.

If `#field` is omitted, callbacks uses `secrets.vault.default_field` (default: `value`).

### Callbacks Vault Auth (Dev + Prod)

Callbacks now authenticates to Vault through a sidecar Vault Agent (AppRole), same pattern as chain/tron gateways.

- Dev compose:
  - service: `dev-callbacks-vault-agent`
  - shared token file: `/run/vault/token`
  - app reads token via `VAULT_TOKEN_FILE=/run/vault/token` and `token_env: VAULT_TOKEN`
- Prod compose:
  - service: `sendico_callbacks_vault_agent`
  - same token sink and env flow
  - AppRole creds are injected at deploy from `CALLBACKS_VAULT_SECRET_PATH` (default `sendico/edge/callbacks/vault`)

Required Vault policy (minimal read-only for KV v2 mount `kv`):

```hcl
path "kv/data/sendico/callbacks/*" {
  capabilities = ["read"]
}

path "kv/metadata/sendico/callbacks/*" {
  capabilities = ["read", "list"]
}
```

Create policy + role (example):

```bash
vault policy write callbacks callbacks-policy.hcl
vault write auth/approle/role/callbacks \
  token_policies="callbacks" \
  token_ttl="1h" \
  token_max_ttl="24h"
vault read -field=role_id auth/approle/role/callbacks/role-id
vault write -f -field=secret_id auth/approle/role/callbacks/secret-id
```

Store AppRole creds for prod deploy pipeline:

```bash
vault kv put kv/sendico/edge/callbacks/vault \
  role_id="<callbacks-role-id>" \
  secret_id="<callbacks-secret-id>"
```

Store webhook signing secrets (example path consumed by `secret_ref`):

```bash
vault kv put kv/sendico/callbacks/client-a/webhook secret="super-secret"
```
