Files
suaveplan/openspec/changes/enterprise-payment-providers/proposal.md
2026-05-27 23:29:53 +01:00

177 lines
5.6 KiB
Markdown

# OpenSpec Change: enterprise-payment-providers
- **Change ID**: enterprise-payment-providers
- **Package**: `@suaveplan/payment-providers`
- **Category**: universal
- **Target path**: `universal/commerce/payment-providers`
- **Status**: IN PROGRESS
- **Date**: 2026-04-24
- **Reference spec**: `/mnt/s/web/suaveplan/enterprise/payment-providers.md`
---
## Summary
Deliver `@suaveplan/payment-providers` on the genesis branch from scratch at enterprise quality. The package provides concrete `PaymentAdapter` implementations for Stripe, PayPal, Square, Mollie, and Adyen. Each adapter wraps the provider's REST API using injectable fetch (no provider SDK dependency), implements the full `PaymentAdapter` interface from `@suaveplan/payment`, handles provider-specific webhook signature verification, and normalises provider error codes to the canonical `PAYMENT.*` code registry. The main-branch version sat at 100% coverage. Genesis adds structured errors, Zod schemas, OTel instrumentation, retry with circuit breaker, and integration-test harnesses.
---
## Current-state audit (genesis)
The package does not exist on genesis yet — this is a fresh build.
---
## Available workspace deps on genesis
| Package | Role |
|---|---|
| `@suaveplan/error` (`workspace:^`) | `PaymentProviderError`; extends `PAYMENT.*` code set |
| `@suaveplan/types` (`workspace:^`) | `LoggerLike`, `Clock` |
| `@suaveplan/payment` (`workspace:^`) | `PaymentAdapter` interface; `PaymentIntent`, `PaymentWebhookEvent` types |
| `@suaveplan/retry` (`workspace:^`) | Retry + circuit breaker for provider API calls |
| `@suaveplan/crypto` (`workspace:^`) | HMAC webhook signature verification |
| `zod` (`catalog:forms`) | Provider response schema validation |
| `@opentelemetry/api` (`catalog:observability`) | Spans + counters |
Dev deps: `vitest`, `@vitest/coverage-istanbul` (all `catalog:testing`).
---
## Public API surface
### Provider factories
```ts
function createStripeAdapter(options: StripeAdapterOptions): PaymentAdapter
function createPayPalAdapter(options: PayPalAdapterOptions): PaymentAdapter
function createSquareAdapter(options: SquareAdapterOptions): PaymentAdapter
function createMollieAdapter(options: MollieAdapterOptions): PaymentAdapter
function createAdyenAdapter(options: AdyenAdapterOptions): PaymentAdapter
```
All option types share a common base:
```ts
interface BaseAdapterOptions {
apiKey: string
webhookSecret?: string
environment?: 'sandbox' | 'production' // default 'production'
retryOptions?: RetryOptions
fetch?: typeof globalThis.fetch
clock?: Clock
logger?: LoggerLike
}
interface StripeAdapterOptions extends BaseAdapterOptions {
apiVersion?: string // default 'latest'
}
interface PayPalAdapterOptions extends BaseAdapterOptions {
clientId: string
clientSecret: string
}
interface AdyenAdapterOptions extends BaseAdapterOptions {
merchantAccount: string
liveUrlPrefix?: string
}
```
### Provider-normalised types
Each provider's raw response is normalised to `PaymentIntent` via a per-provider mapper; these mappers are exported for testing:
```ts
function normalizeStripePaymentIntent(raw: unknown): PaymentIntent
function normalizePayPalOrder(raw: unknown): PaymentIntent
function normalizeSquarePayment(raw: unknown): PaymentIntent
function normalizeMolliePayment(raw: unknown): PaymentIntent
function normalizeAdyenPayment(raw: unknown): PaymentIntent
```
### Error codes
Provider errors are wrapped in `PaymentError` with existing `PAYMENT_PROVIDER_ERROR` code plus an added detail field:
```ts
interface PaymentProviderErrorDetail {
provider: string
providerCode?: string
providerMessage?: string
}
```
---
## Genesis additions
1. **Zod schemas** for all provider-specific option types and raw response shapes.
2. **Sandbox/production switching** — `environment: 'sandbox'` routes to provider test endpoints automatically.
3. **Idempotency key passthrough** — all create/capture/refund calls forward the caller-supplied idempotency key as the provider-specific header (`Idempotency-Key` for Stripe, etc.).
4. **Circuit breaker** — wraps all provider API calls via `@suaveplan/retry`; opens after 5 consecutive provider errors.
5. **OTel instrumentation** — span `payment_provider.api_call` with attributes `payment_provider.name`, `payment_provider.method`; counter `payment_provider.api_total`; histogram `payment_provider.api_duration_ms`.
6. **Provider error normalisation** — 4xx/5xx provider responses are mapped to the closest `PAYMENT.*` error code with provider details preserved in the error context.
---
## File layout
```text
universal/commerce/payment-providers/
package.json
tsconfig.json
vitest.config.ts
src/
index.ts
error-codes.ts
constants/
index.ts
types/
common.ts
common.md
providers/
stripe/
stripe.ts
stripe.md
stripe.types.ts
stripe.test.ts
index.ts
paypal/
paypal.ts
paypal.md
paypal.types.ts
paypal.test.ts
index.ts
square/
square.ts
square.md
square.types.ts
square.test.ts
index.ts
mollie/
mollie.ts
mollie.md
mollie.types.ts
mollie.test.ts
index.ts
adyen/
adyen.ts
adyen.md
adyen.types.ts
adyen.test.ts
index.ts
__benchmarks__/
payment-providers.bench.ts
tests/
integration.test.ts
```
---
## Impact
**Downstream consumers**: `@suaveplan/booking`, any server-side checkout flow.
**Workspace dep prerequisites**: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/payment`, `@suaveplan/retry`, `@suaveplan/crypto`.