Initial Commit
This commit is contained in:
176
openspec/changes/enterprise-payment-providers/proposal.md
Normal file
176
openspec/changes/enterprise-payment-providers/proposal.md
Normal file
@@ -0,0 +1,176 @@
|
||||
# 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`.
|
||||
Reference in New Issue
Block a user