89 lines
7.7 KiB
Markdown
89 lines
7.7 KiB
Markdown
# Tasks — add @suaveplan/payment
|
||
|
||
> Every checkbox MUST reflect work actually done in this change. Retroactive ticking is forbidden.
|
||
|
||
## 1. Spec authoring
|
||
|
||
- [x] 1.1 Read `../suaveplan/enterprise/payment.md` end-to-end.
|
||
- [x] 1.2 Read upstream source at `../suaveplan/packages/universal/payment/src/` end-to-end.
|
||
- [x] 1.3 Read `openspec/AGENTS.md` §13 + §14.
|
||
- [x] 1.4 Draft `proposal.md` from template.
|
||
- [x] 1.5 Fill `## Source mapping` table — every requirement cites line range or appears in the "no source line" table with justification.
|
||
- [x] 1.6 Draft `specs/payment/spec.md` from template.
|
||
- [x] 1.7 Every requirement carries a `**Verified by:**` line at draft time.
|
||
|
||
## 2. Implementation
|
||
|
||
- [x] 2.1 `src/types/payment.ts` — `PaymentStatus`, `PaymentMethod{,Type}`, `CardBrand`, `PaymentIntent`, `PaymentProvider`, `PaymentEventMap`, `Refund{,Status,Reason,Input}`, `Dispute{,Evidence}`, `CreatePaymentIntentInput`, `VALID_TRANSITIONS` (frozen).
|
||
- [x] 2.2 `src/error-codes/error-codes.ts` — `PAYMENT_CODES` (13 codes) via `defineCodes`; `PaymentError extends SuaveplanError<PaymentErrorCode>` with `intentId`/`currentStatus`/`targetStatus`/`ageMs` discriminants; 12 factory functions.
|
||
- [x] 2.3 `src/hooks/hooks.ts` — generic `Hooks<TMap>` + `paymentHooks` singleton + `onPaymentProcessing` shortcut.
|
||
- [x] 2.4 `src/engine/engine.ts` — `PaymentEngine` over `EventBus<PaymentEventMap>`, state-machine enforcement, refund-balance guard, hook pipeline, explicit `markFailed`/`openDispute`/`closeDispute` emitters.
|
||
- [x] 2.5 `src/webhook/webhook.ts` — `WebhookVerifier` using `@suaveplan/crypto-hash` HMAC + `@suaveplan/crypto-utils` `constantTimeEqual`; injectable `now()`.
|
||
- [x] 2.6 `src/receipt/receipt.ts` — `ReceiptGenerator` + `resetReceiptCounter` + plain-text renderer; injectable `now()`/`nextId`.
|
||
- [x] 2.7 `src/gateway/types.ts` — `PaymentGateway` + `GatewayChargeStatus` + `GatewayResult` + `GatewayCharge` + `ValidationResult` + `ChargeOptions`.
|
||
- [x] 2.8 `src/gateway/test.ts` — `TestGateway` + `resetChargeCounter`; injectable `now()`.
|
||
- [x] 2.9 `src/gateway/stripe.ts` — `StripeGateway` over injected `FetchLike`; typed-error wrap; status map.
|
||
- [x] 2.10 `src/gateway/paypal.ts` — `PayPalGateway` over injected `FetchLike`/`now`/`btoa`; OAuth token cache.
|
||
- [x] 2.11 `src/fraud/fraud.ts` — `FraudDetector`; injectable `now()`.
|
||
- [x] 2.12 `src/refund/refund.ts` — `RefundManager` + `resetRefundCounter`; typed `PaymentError`s; injectable `now()`/`nextId`.
|
||
- [x] 2.13 `src/retry/retry.ts` — `PaymentRetrier`; injectable `random()`/`sleep()`.
|
||
- [x] 2.14 `src/tax/tax.ts` — `TaxCalculator`.
|
||
- [x] 2.15 `src/tokenization/tokenization.ts` — `CardTokenizer`; typed `PaymentError(INVALID_CARD)`; injectable `SubtleCrypto`/`now()`.
|
||
- [x] 2.16 `src/reconciliation/reconciliation.ts` — `PaymentReconciliation`; injectable `now()`.
|
||
- [x] 2.17 `src/index.ts` — explicit named root barrel re-exporting every public symbol.
|
||
- [x] 2.18 Per-feature `index.ts` barrels — explicit named re-exports only.
|
||
- [x] 2.19 `package.json` at `0.1.0` with `workspace:^` for `@suaveplan/{error,events,money,crypto-hash,crypto-utils}` and `catalog:build` for `tslib`; 16 subpath exports; `sideEffects: false`.
|
||
- [x] 2.20 `vite.config.ts` + `tsconfig{,.lib}.json` + `vitest.config.ts` + `tests/setup/polyfills.ts`.
|
||
|
||
## 3. Tests
|
||
|
||
- [x] 3.1 `src/error-codes/error-codes.test.ts` — registry shape; every code reachable from a factory; discriminants set / unset; cause passthrough on the three cause-bearing factories.
|
||
- [x] 3.2 `src/hooks/hooks.test.ts` — no-op pass-through; priority ordering; async handler support; unsubscribe idempotence; clear / count; singleton + shortcut.
|
||
- [x] 3.3 `src/engine/engine.test.ts` — every lifecycle method, every transition guard, every provider-error wrap (Error + non-Error throws), out-of-band emitters, `canTransition` matrix.
|
||
- [x] 3.4 `src/webhook/webhook.test.ts` — sign determinism; verify valid + expired + future + bad-sig + bad-length-sig + non-hex-sig + odd-length-sig + tampered-body + invalid-JSON + custom tolerance + SHA-512 + Date.now fallback.
|
||
- [x] 3.5 `src/receipt/receipt.test.ts` — structured generate, injected nextId + taxLabel, plain-text full + minimal render.
|
||
- [x] 3.6 `src/gateway/test.test.ts` — happy + delay + failure + missing charge + shouldFail mid-stream for capture / refund + validate matrix.
|
||
- [x] 3.7 `src/gateway/stripe.test.ts` — success / canceled / unknown / HTTP-error paths + capture (with/without amount) + refund (success + fallback) + get (with/without charges array) + validate matrix + baseUrl normalisation.
|
||
- [x] 3.8 `src/gateway/paypal.test.ts` — auth + create + token cache + token refresh + auth failure + order failure + custom baseUrl + capture (with/without amount) + refund (success + no-capture + PENDING) + get (aggregation + empty units + unknown status) + validate matrix + empty body.
|
||
- [x] 3.9 `src/fraud/fraud.test.ts` — clean allow, missing-customer flag, high-amount flag, velocity → block, between-thresholds review, score cap, reset, early-return when no customerId.
|
||
- [x] 3.10 `src/refund/refund.test.ts` — every typed error reachable, summary balances, fullyRefunded flag, byReason filter, canRefund matrix, injected nextId.
|
||
- [x] 3.11 `src/retry/retry.test.ts` — success / retry-success / non-retryable result / non-retryable thrown / exhaustion / non-Error wrap / default sleep / calculateDelay matrix (no-jitter / cap / +jitter / -jitter never-negative).
|
||
- [x] 3.12 `src/tax/tax.test.ts` — fallback default, region override, removeRate, exclusive, inclusive, exempt, empty input.
|
||
- [x] 3.13 `src/tokenization/tokenization.test.ts` — tokenize + custom prefix + bad Luhn + bad month + expired + Luhn matrix + brand matrix (8 brands + unknown).
|
||
- [x] 3.14 `src/reconciliation/reconciliation.test.ts` — matched + discrepancy + unmatched (both sides) + status normalisation + reconciledAt clock.
|
||
- [x] 3.15 Every `it(...)` carries `{ timeout: 5000 }`.
|
||
|
||
## 4. Documentation
|
||
|
||
- [x] 4.1 Sibling `.md` for every implementation `.ts` (16 modules) — ≥200 words, basic + advanced examples, full API reference.
|
||
- [x] 4.2 `README.md` linking every co-located `.md` under `## Modules`.
|
||
|
||
## 5. Pre-archive verification (the 5-gate triple)
|
||
|
||
- [ ] 5.1 `bun run check` — Biome 0/0/0 across the monorepo.
|
||
- [ ] 5.2 `bunx turbo lint typecheck test --filter=@suaveplan/payment` — green.
|
||
- [ ] 5.3 `bunx turbo test:coverage --filter=@suaveplan/payment` — 100/100/100/100.
|
||
- [ ] 5.4 `bunx turbo build --filter=@suaveplan/payment` — green.
|
||
- [ ] 5.5 Banned-pattern scan (`@deprecated`/`TODO`/`FIXME`/`ts-ignore`/`ts-expect-error`/`.skip`/`.only`) — zero output.
|
||
|
||
## 6. Pre-archive 9-row checklist (AGENTS.md §13)
|
||
|
||
- [ ] 6.1 Generics threaded; no `any`.
|
||
- [ ] 6.2 Zod schemas wired at every declared boundary — N/A (deferred per `## Out of scope`).
|
||
- [ ] 6.3 Every error code in `PAYMENT_CODES` thrown by a production path.
|
||
- [ ] 6.4 Strict-mode behaviours tested both on and off — N/A (no strict-mode toggle).
|
||
- [ ] 6.5 OTel instruments emitted from production paths — N/A (deferred per `## Out of scope`).
|
||
- [ ] 6.6 Lifecycle dedup tested where claimed — N/A (idempotency deferred).
|
||
- [ ] 6.7 No retroactive tick.
|
||
- [ ] 6.8 No `export *` in any feature-module barrel.
|
||
- [ ] 6.9 No direct `vitest` / `bun:test` imports in test files.
|
||
|
||
## 7. Archive
|
||
|
||
- [ ] 7.1 Fold spec delta into `openspec/specs/payment/spec.md`.
|
||
- [ ] 7.2 Move `openspec/changes/add-payment/` → `openspec/archive/2026-05-17-add-payment/`.
|
||
- [ ] 7.3 Refresh `MANIFEST.md` via `bun scripts/folder-reorg/generate-manifest.ts`.
|
||
- [ ] 7.4 Update `STATUS.md` to flip `@suaveplan/payment` from `–` → `✅`.
|
||
- [ ] 7.5 Update `SUMMARY.md` with the shipped surface.
|
||
- [ ] 7.6 `bunx markdownlint-cli2 --fix` across touched markdown.
|