Connect local SXCHNGE to the Sendico stand
This commit was merged in pull request #53.
This commit is contained in:
1 parent
34d8ef18d1
commit
a5689876ff
14 files changed
+336
-9
No files matched your search
@@ -1,5 +1,7 @@
|
||||
# Local development
|
||||
|
||||
For the connected Sendico stand, see [local Sendico integration](local-sendico.md).
|
||||
|
||||
Task [#42](https://git.sendico.io/tech/sxchnge/issues/42),
|
||||
[PR #43](https://git.sendico.io/tech/sxchnge/pulls/43), branch `dev-env-42`.
|
||||
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
# Local Sendico integration
|
||||
|
||||
Task [#52](https://git.sendico.io/tech/sxchnge/issues/52), branch `local-stand-52`,
|
||||
based on `payments-50` / [PR #51](https://git.sendico.io/tech/sxchnge/pulls/51).
|
||||
The local Sendico checkout uses `payments-2896` /
|
||||
[PR #2897](https://git.sendico.io/tech/sendico/pulls/2897). Merge the prerequisites
|
||||
before this infrastructure PR. No PR is merged by local startup.
|
||||
|
||||
## Running the configured stands
|
||||
|
||||
Start Sendico first from its checkout using its documented Make workflow. Its
|
||||
Product API must respond at `http://localhost:8080/api/v1/health`. Then, here:
|
||||
|
||||
```sh
|
||||
make build
|
||||
make up
|
||||
make test-dev
|
||||
```
|
||||
|
||||
Open [SXCHNGE](https://localhost:5126),
|
||||
[Sendico Product](http://localhost:3000), and
|
||||
[Sendico Backoffice](http://localhost:4000).
|
||||
SXCHNGE's Caddy CA is exported to `.local/dev/ca.pem`; trust that public CA in
|
||||
the browser/OS if necessary. Bootstrap does not modify the system trust store.
|
||||
|
||||
The optional integration is selected by ignored `.local/dev/sendico/settings.env`.
|
||||
Make and the containerized bootstrap both include
|
||||
`infra/local/sendico/compose.yml` whenever that file exists. Standalone SXCHNGE
|
||||
still uses six services. The connected stack adds one `sendico` session worker.
|
||||
`make ps`, `make logs`, and `make down` include it automatically.
|
||||
|
||||
## Identity and configuration
|
||||
|
||||
The configured local stand has a dedicated `SXCHNGE Local` organization, active
|
||||
integration account and account-bound confidential API client. The account is
|
||||
an organization member with organization read/update, ledger read, payment
|
||||
create/read, and recipient create/read/update permissions. Customer subjects
|
||||
remain independent from that account. No pooled balances, customer funds or
|
||||
payout destinations are seeded by this setup. Existing stand data is retained.
|
||||
This identity was created through a one-time local administrative bootstrap;
|
||||
runtime traffic and session creation use only the public HTTP API.
|
||||
|
||||
For another stand, an operator must first provision the organization, account,
|
||||
client and grants in Sendico. Resolve actual IDs from that stand; do not copy
|
||||
another environment's references. Initialize SXCHNGE's Vault using `make up`
|
||||
before configuring the integration. Supply this JSON privately on stdin:
|
||||
|
||||
```json
|
||||
{
|
||||
"organization_ref": "<organization object ID>",
|
||||
"source_account_ref": "<integration account object ID>",
|
||||
"client_id": "<confidential client ID>",
|
||||
"device_id": "sxchnge-local-bff",
|
||||
"login": "<integration login>",
|
||||
"password": "<integration password>",
|
||||
"client_secret": "<confidential client secret>"
|
||||
}
|
||||
```
|
||||
|
||||
```sh
|
||||
# Save operator input outside tracked files, with mode 0600. Never echo it.
|
||||
make sendico < /private/path/sendico-input.json
|
||||
make up
|
||||
make test-dev
|
||||
```
|
||||
|
||||
`make sendico` validates references and identifiers, stores only login/password/
|
||||
client_secret at Vault `kv/services/bff/sendico`, and writes the non-secret client,
|
||||
device, organization and source references into ignored local settings. The BFF
|
||||
runtime is generated from `infra/local/bff/runtime.yml` with the existing
|
||||
`api.sendico` configuration. Re-run configuration after changing that base YAML.
|
||||
Remove the temporary input file once credentials have been stored in Vault.
|
||||
No Sendico configuration parameters or application transport rules change.
|
||||
|
||||
## Connection and renewal
|
||||
|
||||
The session worker shares BFF's network namespace and binds a private loopback
|
||||
TCP bridge at `127.0.0.1:18081`, forwarding to
|
||||
`host.docker.internal:8080`. This uses the local stand's existing public HTTP API
|
||||
port; it requires a local Docker engine with `host.docker.internal` support, as
|
||||
provided by Docker Desktop. The bridge publishes no new host port. The adapter's
|
||||
existing HTTPS requirement and loopback-only HTTP exception remain intact.
|
||||
|
||||
The worker authenticates to Vault with its own AppRole, reads exactly
|
||||
`services/bff/sendico`, and revokes its five-minute Vault token after reading.
|
||||
It cannot read Mongo credentials, JWT signing keys, NATS auth or administrator
|
||||
material. Its initial login uses Sendico's public `/accounts/login/api` grant,
|
||||
validates the access token's source account, full-session status and expiry, and
|
||||
atomically publishes the token in a volume mounted read-only by BFF. Credentials
|
||||
and response bodies stay in private tmpfs files and never appear in logs or
|
||||
command arguments. Flutter receives no platform credentials.
|
||||
|
||||
Successful login repeats every 20 minutes before the one-hour access token
|
||||
expires. A failure retains the prior token, logs one generic actionable message,
|
||||
and retries after five minutes. The worker becomes unhealthy after 25 minutes
|
||||
without renewal or when the upstream health endpoint fails; the adapter
|
||||
separately rejects expired or mismatched tokens.
|
||||
BFF waits for a recent token at startup. Following credential changes, restart
|
||||
the worker with `make up` followed by the Compose restart command below, or wait
|
||||
for its next renewal. Never change the integration account on an existing
|
||||
financial environment without reviewing resource and idempotency bindings.
|
||||
|
||||
```sh
|
||||
docker compose --project-directory . -f infra/local/compose.yml \
|
||||
-f infra/local/sendico/compose.yml --env-file .local/dev/images.env restart sendico
|
||||
```
|
||||
|
||||
`make test-dev` checks seven healthy services, verified browser TLS, the Vault
|
||||
layout and least-privilege identities, Mongo transactions/lease rotation, and
|
||||
authenticated Sendico currency and ledger reads through the same loopback
|
||||
connection and token used by BFF. It sends no email and executes no payment.
|
||||
An empty wallet is expected until dedicated subject-bound currency ledgers and
|
||||
saved methods are provisioned as described in [payment provisioning](payments.md).
|
||||
|
||||
## Recovery
|
||||
|
||||
The existing stand had application processes stopped inside still-running Air
|
||||
containers after a NATS disconnect and Mongo replica-state interruption. Restore
|
||||
discovery first, then Treasury and the other service announcers. Wait until each
|
||||
stage is registered before restarting dependent services: billing fees and
|
||||
Ledger, then Limits/gateways/quotation/receiving routes, then payment orchestrator,
|
||||
compliance assessment and Product BFF. The Sendico Makefile provides its ordered
|
||||
backend startup workflow. Inspect current logs and health instead of assuming a
|
||||
running development container has a live application process. Do not delete
|
||||
volumes or reset financial data to recover service registration.
|
||||
|
||||
If an old Caddy leaf certificate expires while the stack is stopped, restart
|
||||
frontend after startup so Caddy issues a fresh certificate. Preserve `caddy-data`
|
||||
and the established CA. A subsequent verified TLS check must succeed.
|
||||
|
||||
## Acceptance and operator UX review
|
||||
|
||||
Validated on 2026-10-16: `make build`, `make up`, `make test-dev-tooling`,
|
||||
`make test-dev-infra`, `make test-dev`, and `git diff --check` passed. Both product
|
||||
sites, Sendico Backoffice and both API health endpoints returned HTTP 200;
|
||||
SXCHNGE's browser endpoint was checked with its exported CA. All Sendico services
|
||||
with health checks were healthy. Forced worker restart issued a different valid
|
||||
same-account token and preserved successful authenticated currency/ledger reads.
|
||||
The existing notification sender edit remains outside this task's commit.
|
||||
|
||||
The setup journey starts with the operator's Make invocation and completes when
|
||||
Compose confirms service readiness; `make test-dev` additionally confirms the
|
||||
authenticated integration. Existing command exit codes and Compose progress /
|
||||
health states distinguish configuration, dependency, authentication and readiness
|
||||
failures. A renewed-session log records credential recovery, while stale renewal
|
||||
or upstream outage changes container health. Each new operator invocation is a
|
||||
new attempt; worker retries remain within that process's lifetime. Command wall
|
||||
time measures setup duration. Interrupted commands are incomplete attempts, not
|
||||
successful launches. These are local operator signals, with no retained analytics
|
||||
or cross-invocation conversion/abandonment reporting added.
|
||||
|
||||
The UX review covered missing bootstrap material, malformed operator input,
|
||||
authentication failure, retained retry context, stale TLS recovery, successful
|
||||
startup and confirmed API access. Commands reuse existing Make/Compose patterns,
|
||||
errors give a recovery action, and success follows readiness. No secret values
|
||||
appear in terminal feedback. Product layouts, focus and screen-reader behavior
|
||||
are unchanged; browser interaction and funded payment settlement are not claimed
|
||||
by HTTP readiness checks. No email or payment was sent during validation.
|
||||
Reference in new issue
Block a user