# wallet_integrations

External integration adapter layer for the MercuryPay wallet platform.

## Purpose

This OTP app implements the port-and-adapter pattern (ADR 0008) for all outbound payment provider interactions and inbound webhook/callback processing. It isolates domain apps from provider-specific protocols and enforces financial consistency, resilience, and security controls at the integration boundary.

## Public Interface

Domain apps interact with this app through commands only:

```elixir
# Initiate an outbound payment via a configured provider
WalletIntegrations.Commands.InitiatePayment.execute(request, opts)

# Poll current status from the provider
WalletIntegrations.Commands.GetPaymentStatus.execute(provider_ref, opts)

# Cancel a pending payment (when supported by provider)
WalletIntegrations.Commands.CancelPayment.execute(provider_ref, opts)

# Initiate a refund (when supported by provider)
WalletIntegrations.Commands.RefundPayment.execute(provider_ref, amount, opts)

# Ingest and process an inbound provider callback/webhook
WalletIntegrations.Commands.IngestCallback.execute(callback_params, opts)
```

## Architecture

```
Domain Apps (wallet_transfers, etc.)
       |
       v (commands)
WalletIntegrations
  ├── ProviderAdapter behaviour       — port contract (ADR 0008)
  ├── AdapterRequest / AdapterResult  — normalized models
  ├── Adapters
  │   ├── StripeAdapter               — Stripe sandbox adapter
  │   └── StubAdapter                 — test/CI stub
  ├── PaymentRequestStore             — outbound request lifecycle
  ├── CallbackStore                   — inbound callback lifecycle
  ├── InboxStore                      — dedup/replay protection (ADR 0002)
  ├── IntegrationExceptionStore       — mismatch/unknown-outcome records
  ├── CircuitBreaker                  — per-provider/operation breaker (ADR 0008)
  ├── RetryPolicy                     — timeout/retry/backoff config (ADR 0008)
  ├── CallbackVerifier                — signature + freshness validation
  ├── SecretProvider                  — credential loading (no plaintext)
  └── Workers
      ├── PaymentWorker               — async outbound dispatch
      └── CallbackWorker              — async callback processing
```

## Provider Configuration

Configure the active adapter and credentials via application environment:

```elixir
# config/config.exs
config :wallet_integrations,
  payment_adapter: WalletIntegrations.Adapters.StripeAdapter,
  secret_provider: WalletIntegrations.SecretProvider.EnvSecretProvider,
  http_client: WalletIntegrations.Http.HttcClient
```

For test/CI, StubAdapter is used by default via `Application.get_env` with no configuration required.

## Failure Policy (ADR 0008)

- **Timeout**: connect, read, and overall deadline configured per `RetryPolicy`.
- **Retry**: exponential backoff with jitter; only retryable (transient) failures retried.
- **Circuit breaker**: per-provider-operation; opens on consecutive failures, probes in half-open mode.
- **Unknown outcomes**: routed to reconciliation via `IntegrationExceptionStore`; no duplicate side effects.
- **Callback dedup**: `InboxStore` deduplicates by message_id before any processing occurs.

## Security Controls

- Provider credentials loaded exclusively via `SecretProvider` (never from plaintext config).
- Webhook signatures verified against provider secret before any processing.
- Timestamp freshness enforced within configurable tolerance window (default 300 s).
- Raw callback payloads hashed for audit traceability; PII not logged.

## Dependency Boundary

Allowed inbound dependencies (ADR 0001):
- `wallet_transfers` — read transfer records for payment dispatch
- `wallet_shared_kernel`, `wallet_api_contracts`, `wallet_observability`, `wallet_events`

Forbidden: `wallet_ledger`, `wallet_accounts` — ledger posting remains in domain apps.
