# 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": "", "source_account_ref": "", "client_id": "", "device_id": "sxchnge-local-bff", "login": "", "password": "", "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 ``` A BFF container restart can leave its session worker in the old shared network namespace. The worker checks Vault DNS every ten seconds, with a five-second lookup limit. Three consecutive failures log a credential-free recovery reason and terminate the session process; Docker's restart policy then attaches it to the BFF's current namespace. A successful lookup resets the counter, so transient DNS failures do not immediately restart the worker. Container recreation changes the BFF container ID as well as its namespace. Bootstrap and credential-rotation tooling recreate BFF and its configured session worker together. Compose also marks the session dependency for restart when BFF is explicitly updated. For a manual forced recreation, select both services: ```sh docker compose --project-directory . -f infra/local/compose.yml \ -f infra/local/sendico/compose.yml --env-file .local/dev/images.env \ up -d --no-deps --force-recreate --wait bff sendico ``` The parent process cleans up its bridge, DNS monitor and renewal delay on exit. This recovery retains the configured provider URL, account and replay namespace. `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. Signup and wallet access automatically ensure subject-bound RUB, USDT and USDC ledgers as described in [account setup](payments.md#automatic-currency-accounts-72). Deploy the provider prerequisite and grant ledger-create permission first. Saved funding and payout methods remain separate from currency-account setup. ## 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 Recovery follow-up for [task #57](https://git.sendico.io/tech/sxchnge/issues/57) / [PR #59](https://git.sendico.io/tech/sxchnge/pulls/59), validated on 2026-10-19: `make test-dev-tooling`, `make test-dev-rotation`, Compose configuration validation, `sh infra/local/tools.sh verify` and `git diff --check` pass. A BFF-only restart triggered automatic session restart and restored matching network namespaces; paired recreation also finished healthy. Rotation observed three real Vault pool replacements, an unchanged BFF process and 534 transaction-backed requests with zero failures. The final check verifies all seven SXCHNGE services, browser HTTPS, Vault/database boundaries and authenticated Sendico currency/ledger reads. An earlier check failed because Sendico's ledger announcement connection was closed; restoring Discovery and its service announcers in dependency order recovered that existing stand. No Sendico source or financial data was changed, and no email or payment was sent. This follow-up changes shell/Compose tooling; it does not rerun the earlier full Go/Flutter suite for unchanged product source. 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.