feat(payments): PaymentProcessor interface + Stripe adapter#1
Open
jfuginay wants to merge 1 commit into
Open
Conversation
Introduce a server-side PaymentProcessor interface so the v0.2 Square adapter and the v0.2 inventory-deduction work can land on a single abstraction instead of two parallel processor-specific code paths. - apps/web/lib/payments/ — interface, types, errors, Stripe adapter - POS, checkout, and receipt server actions now go through getProcessor() instead of importing Stripe directly - Connection-token route stays Stripe-specific (intentional: client-SDK bootstrap differs too much per processor to abstract cleanly) - Behavior unchanged: same Stripe calls, same DB writes, same Payment row shape (Stripe-specific columns kept for v0.1) Verification: bun typecheck clean; 19/19 Playwright e2e green including the cash-refund happy path. Next PRs: 1. Schema migration: add Payment.processor + generic processorRef 2. Square adapter implementing PaymentProcessor 3. OrderClosed event + InventoryComponent deductions hung off it Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Lay the rail for v0.2 payment work — Square as alternate processor and
InventoryComponentdeductions — by routing all payment-side calls through a single server-side interface instead of importinggetStripe()directly in four places.apps/web/lib/payments/—PaymentProcessorinterface, shared types,ProcessorRef,ProcessorNotConfiguredError, and a Stripe adapter that wraps the existing flows.pos/[slug]/actions.ts,pos/[slug]/checkout/[orderId]/actions.ts,pos/[slug]/receipt/[orderId]/actions.ts) now callgetProcessor()instead of touching the Stripe SDK.apps/web/app/api/stripe/connection-token/route.ts. Client-SDK bootstrap (Stripe Terminal connection tokens, Square Reader OAuth) differs too much per processor to abstract cleanly — those live in processor-specific routes.Behavior is identical to before: same Stripe API calls, same DB writes, same
Paymentrow shape (Stripe-specific columns kept for v0.1).Why this matters for v0.2
The reason the abstraction is the first PR in this sequence is that the next two PRs both hang off it:
Payment.processor+ a genericprocessorRefcolumn so a Square payment can be persisted without boltingsquarePaymentIdonto the schema.apps/web/lib/payments/square-adapter.tsimplementing the same interface.getProcessor()will dispatch on a per-Businesssetting (business.cardProcessor) when this lands.OrderClosedevent + inventory deductions —Order.close()becomes a single domain entry point. TheInventoryComponentdeduction readsOrderLinesnapshots and decrements stock when the event fires — regardless of which processor handled the card. There's a placeholder comment incaptureCardPaymentmarking the plug-in point.This sequencing avoids the trap of writing
stripe.paymentIntent.succeeded → decrementand then later writingsquare.payment.completed → decrementas two separate webhook handlers — two code paths, two test surfaces, two ways to leak inventory on retries.What's still Stripe-flavored
The DB schema.
Payment.stripePaymentIntentIdandstripeChargeIdcolumns remain. The adapter writes itsProcessorRef.intentIdtostripePaymentIntentIdfor now. Migrating those columns toprocessor+processorRefis the next PR — it requires a Prisma migration and a backfill, which would have made this PR much louder.Test plan
bun run typecheckclean across all workspacesrefund a cash sale → status flips to refundedNon-goals (deliberately deferred)
processorRefparseWebhookis not on the interface yet — Stripe webhooks aren't wired in v0.1, so adding that now would be designing for nothing)OrderClosedevent emission and the inventory subscriber🤖 Generated with Claude Code