feat(ADM-018): completed feature
This commit is contained in:
38
work/artifacts/F-023/architect.md
Normal file
38
work/artifacts/F-023/architect.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# Architect — F-023 Payments: provider interface + Stripe + webhooks
|
||||
|
||||
## Feature
|
||||
F-023 introduces real payment processing without coupling domain to Stripe.
|
||||
|
||||
## Design
|
||||
|
||||
### Module boundaries
|
||||
Create `project/src/modules/payments/` with domain/application/infrastructure/api/tests. Payments owns `payments_transactions`; domain code never imports the Stripe SDK.
|
||||
|
||||
### Data model
|
||||
Add migration `017_payments.js`:
|
||||
- `payments_transactions`: id, provider text, provider_event_id text unique per provider, provider_payment_id text, order_id uuid, amount_cents integer, currency text, status text, raw jsonb, created_at timestamptz.
|
||||
- CHECK `status IN ('requires_payment','succeeded','failed','refunded','chargeback')`.
|
||||
- UNIQUE `(provider, provider_event_id)` for idempotency.
|
||||
|
||||
### Payment provider interface
|
||||
- `PaymentProvider.createIntent(input)` and `PaymentProvider.verifyWebhook(rawBody, signature)` returning a typed `PaymentEvent` or throwing.
|
||||
- Domain never touches Stripe SDK; only the Stripe adapter does.
|
||||
|
||||
### Webhook flow
|
||||
- `POST /payments/webhook` reads raw body + signature header.
|
||||
- Verifies signature with `STRIPE_WEBHOOK_SECRET` (or env-derived) — invalid -> 400.
|
||||
- Looks up `(provider, provider_event_id)` in transactions; if seen, return 200 without re-processing (idempotent).
|
||||
- Maps Stripe events to `PaymentEvent` (`PaymentSucceeded`, `PaymentFailed`, `PaymentRefunded`, `ChargebackCreated`) and processes them: persist transaction, call `OrderService.transition` and emit event through `OrderEventPublisher`.
|
||||
|
||||
### API
|
||||
- `POST /payments/webhook` public (signature-protected).
|
||||
- Admin/dev `GET /payments/transactions/:orderId` for inspection.
|
||||
|
||||
### Domain events
|
||||
- Emit `OrderPaid`/`OrderCancelled`/`OrderRefunded` via `OrderEventPublisher` already exposed by orders.
|
||||
|
||||
## Acceptance trace
|
||||
- Domain code contains zero Stripe SDK imports.
|
||||
- Bad signature -> 400, no DB row.
|
||||
- Replayed event -> single processed transaction.
|
||||
- PaymentSucceeded -> order state PAID, event emitted.
|
||||
Reference in New Issue
Block a user