This commit is contained in:
33
openspec/changes/update-payment-routing-policy/design.md
Normal file
33
openspec/changes/update-payment-routing-policy/design.md
Normal file
@@ -0,0 +1,33 @@
|
||||
## Context
|
||||
|
||||
The August backend change is intentionally compatible at the HTTP surface: the two C端 payment creation paths remain unchanged, while merchant selection and retry semantics move to a stricter merchant-pool policy. The H5 client already has separate WeChat, Alipay, and wallet result handling, submit guards, and post-payment status refreshes; this change must tighten creation-attempt boundaries without changing those payment contracts.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
- Goals: make one accepted user submission correspond to one payment-creation attempt; prevent client-side merchant failover and duplicate creation; preserve backend error semantics; keep status reconciliation read-only.
|
||||
- Goals: make the attempt-count implication explicit so UI retries and polling do not silently exceed payment limits.
|
||||
- Non-Goals: changing endpoint paths, adding merchant credentials/IDs to the client, redesigning payment pages, or changing WeChat/Alipay payment invocation contracts.
|
||||
|
||||
## Decisions
|
||||
|
||||
- Decision: merchant selection is opaque to the client. The client sends the documented request payload and never chooses or rotates a merchant.
|
||||
- Decision: classify an API-declared pre-order failure as terminal for that attempt. The UI reports the backend error and exits the submit flow.
|
||||
- Decision: classify timeout/network interruption as unknown rather than failed-success. The client does not create a replacement payment automatically; it refreshes status where supported and leaves any retry to an explicit user action.
|
||||
- Decision: status polling and page refresh use read-only order/recharge queries. They must not call either payment creation endpoint.
|
||||
- Decision: treat every invocation of a payment creation endpoint as an attempt for quota/count semantics, regardless of the eventual payment result.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- A user may need to retry manually after a transient network problem. This is intentional to avoid duplicate payment creation; provide clear “check status/retry” feedback.
|
||||
- A delayed backend result can leave the UI temporarily indeterminate. Reconciliation through existing status APIs reduces this risk without creating another payment.
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. Audit API adapters and all payment callers for hidden retries or merchant parameters.
|
||||
2. Add/adjust terminal and unknown-result branches while retaining existing result handlers.
|
||||
3. Verify read-only status refresh and submit guards across package and wallet flows.
|
||||
4. Roll back the client branch if backend rollout is delayed; endpoint contracts remain backward compatible.
|
||||
|
||||
## Open Questions
|
||||
|
||||
- Which order/recharge status endpoint and polling window should be used for an unknown creation result in each deployment environment?
|
||||
29
openspec/changes/update-payment-routing-policy/proposal.md
Normal file
29
openspec/changes/update-payment-routing-policy/proposal.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Change: Align C端 payment flows with merchant-pool routing policy
|
||||
|
||||
## Why
|
||||
|
||||
The August payment iteration keeps the existing C端 payment creation endpoints, but changes how the backend routes payment creation through its merchant pool. The client must stop assuming that a failed or unknown payment-creation result can be retried against another merchant, otherwise one user action can create duplicate payment attempts and consume payment limits unexpectedly.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Keep `POST /api/c/v1/orders/create` and `POST /api/c/v1/wallet/recharge` as the payment creation endpoints; do not add a merchant ID to client requests.
|
||||
- Treat merchant selection as backend-owned and preserve the selected payment method and existing request fields (`identifier`, package IDs or amount, and WeChat-only `app_type`).
|
||||
- Treat an explicit payment pre-order failure as the terminal result for the current attempt; surface the API error without automatically switching merchants or creating another payment.
|
||||
- Treat timeout, connection interruption, and other unknown payment-creation results as indeterminate; do not automatically switch merchants or repeat payment creation. Any retry must be a deliberate, user-visible action after the applicable order/payment status is reconciled.
|
||||
- Ensure payment-limit and attempt-count behavior is modeled as “every payment creation attempt counts”, rather than “only successful payments count”; client polling/status refresh must never create another payment.
|
||||
- Continue to use the API-defined error codes and messages as the source of truth.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `payment-routing-policy`: Apply merchant-pool routing, terminal-failure, unknown-result, and payment-attempt accounting rules to C端 payment creation.
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
## Impact
|
||||
|
||||
- Affected API adapters: `api/modules/order.js`, `api/modules/wallet.js`.
|
||||
- Affected payment callers: package order, wallet recharge, order-list payment, and shared payment-result/status refresh flows.
|
||||
- No endpoint path or client merchant-selection configuration changes.
|
||||
- Existing WeChat `pay_config`, Alipay `payment_link`, wallet payment, submit guards, and backend status reconciliation remain compatible.
|
||||
@@ -0,0 +1,90 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Payment creation SHALL use the stable C端 API contract
|
||||
|
||||
The client SHALL create package/strong-recharge orders through `POST /api/c/v1/orders/create` and wallet recharge orders through `POST /api/c/v1/wallet/recharge`. It SHALL submit the documented identifier, package or amount fields, and selected `payment_method`; it SHALL submit `app_type` only when required for WeChat payment and SHALL NOT submit a merchant ID.
|
||||
|
||||
#### Scenario: Package order creation uses the stable route
|
||||
|
||||
- **WHEN** a customer confirms a package or strong-recharge order
|
||||
- **THEN** the client SHALL call `POST /api/c/v1/orders/create`
|
||||
- **AND** the request SHALL not contain a client-selected merchant ID
|
||||
|
||||
#### Scenario: Wallet recharge creation uses the stable route
|
||||
|
||||
- **WHEN** a customer confirms a wallet recharge
|
||||
- **THEN** the client SHALL call `POST /api/c/v1/wallet/recharge`
|
||||
- **AND** the request SHALL contain the selected payment method and amount in the documented unit
|
||||
|
||||
### Requirement: Merchant selection SHALL remain backend-owned
|
||||
|
||||
The system SHALL rely on the backend merchant pool to select a payment merchant. The client SHALL not rotate merchants, expose merchant selection, or retry the same creation request against another merchant automatically.
|
||||
|
||||
#### Scenario: Payment creation is accepted
|
||||
|
||||
- **WHEN** the backend receives a valid payment creation request
|
||||
- **THEN** the client SHALL use the returned payment preparation data (`pay_config`, `payment_link`, or wallet result) without attempting merchant selection locally
|
||||
|
||||
### Requirement: Explicit pre-order failure SHALL be terminal for the current attempt
|
||||
|
||||
When a payment creation endpoint returns an explicit failure, the client SHALL treat that attempt as failed, display the API-defined error code/message, and SHALL NOT automatically switch merchants or create another payment.
|
||||
|
||||
#### Scenario: Package order pre-order fails
|
||||
|
||||
- **WHEN** `/api/c/v1/orders/create` returns an error response before payment preparation succeeds
|
||||
- **THEN** the current package/strong-recharge attempt SHALL end as failed
|
||||
- **AND** the client SHALL surface the backend error without an automatic second creation request
|
||||
|
||||
#### Scenario: Wallet recharge pre-order fails
|
||||
|
||||
- **WHEN** `/api/c/v1/wallet/recharge` returns an error response before payment preparation succeeds
|
||||
- **THEN** the current recharge attempt SHALL end as failed
|
||||
- **AND** the client SHALL not switch merchants or silently create a replacement recharge order
|
||||
|
||||
### Requirement: Unknown payment-creation results SHALL not create duplicates
|
||||
|
||||
Timeouts, connection interruptions, and other results where the creation outcome is unknown SHALL be treated as indeterminate. The client SHALL not automatically switch merchants or repeat payment creation, and any status refresh SHALL be read-only.
|
||||
|
||||
#### Scenario: Creation request times out
|
||||
|
||||
- **WHEN** a payment creation request times out or the connection is interrupted before a definitive response is received
|
||||
- **THEN** the client SHALL make no automatic replacement creation request
|
||||
- **AND** the client SHALL allow the existing status-reconciliation flow to determine whether an order or recharge was created
|
||||
|
||||
#### Scenario: Status polling follows an unknown result
|
||||
|
||||
- **WHEN** the client polls or refreshes order/recharge status after an unknown result
|
||||
- **THEN** it SHALL call only read-only status APIs
|
||||
- **AND** it SHALL not count the refresh as a new payment creation attempt or invoke either creation endpoint
|
||||
|
||||
### Requirement: Payment attempt accounting SHALL include every creation attempt
|
||||
|
||||
The client SHALL behave consistently with the backend rule that amount/attempt limits count every invocation of a payment creation endpoint, regardless of whether the resulting payment later succeeds. It SHALL not loop until success or assume a failed/unknown attempt is free.
|
||||
|
||||
#### Scenario: Explicit failure consumes an attempt
|
||||
|
||||
- **WHEN** a payment creation request is sent and the backend returns an explicit failure
|
||||
- **THEN** the client SHALL finish the current flow without automatic repetition
|
||||
- **AND** subsequent creation SHALL require a new deliberate user action
|
||||
|
||||
#### Scenario: Successful payment follows one creation attempt
|
||||
|
||||
- **WHEN** a payment creation request returns valid payment preparation data
|
||||
- **THEN** the client SHALL proceed with the existing WeChat, Alipay, or wallet flow
|
||||
- **AND** status polling or payment-link return handling SHALL not create an additional payment
|
||||
|
||||
### Requirement: Existing payment result contracts SHALL remain compatible
|
||||
|
||||
The routing-policy change SHALL preserve existing WeChat `pay_config`, Alipay `payment_link`, wallet payment, submit-guard, and backend status-reconciliation behavior. API-defined error codes and messages SHALL remain authoritative.
|
||||
|
||||
#### Scenario: WeChat or Alipay preparation succeeds
|
||||
|
||||
- **WHEN** the backend returns valid `pay_config` or `payment_link`
|
||||
- **THEN** the client SHALL invoke the existing corresponding payment flow
|
||||
- **AND** it SHALL determine final success from the existing backend status refresh rather than from a routing decision
|
||||
|
||||
#### Scenario: Backend returns a documented error
|
||||
|
||||
- **WHEN** the API returns a documented error code and message
|
||||
- **THEN** the client SHALL preserve and present that error according to the existing error-handling behavior
|
||||
- **AND** it SHALL not replace it with a merchant-specific or generic retry result
|
||||
19
openspec/changes/update-payment-routing-policy/tasks.md
Normal file
19
openspec/changes/update-payment-routing-policy/tasks.md
Normal file
@@ -0,0 +1,19 @@
|
||||
## 1. Request contract and routing
|
||||
|
||||
- [x] 1.1 Audit order and wallet payment creation adapters to keep the documented endpoint paths and required fields unchanged.
|
||||
- [x] 1.2 Ensure no payment creation request accepts or forwards a merchant ID; keep `app_type` conditional on WeChat payment only.
|
||||
- [x] 1.3 Document the backend-owned merchant-pool selection and the fact that the client must issue one creation request per accepted user action.
|
||||
|
||||
## 2. Failure and unknown-result handling
|
||||
|
||||
- [x] 2.1 Handle explicit pre-order failures as terminal for the current attempt and display the backend-provided error code/message.
|
||||
- [x] 2.2 Ensure timeout, connection interruption, and other unknown creation results do not trigger merchant switching or a second automatic creation request.
|
||||
- [x] 2.3 Keep status polling/refresh flows read-only; they must reconcile order or recharge state without creating another payment.
|
||||
- [x] 2.4 Provide a deliberate, user-visible retry path only after the current order/payment state can be safely reconciled, preserving existing submit guards.
|
||||
|
||||
## 3. Attempt accounting and regression verification
|
||||
|
||||
- [x] 3.1 Verify client behavior does not treat a failed or unknown attempt as free and does not loop until payment succeeds.
|
||||
- [x] 3.2 Verify package order creation and wallet recharge each make at most one payment-creation call per accepted submission.
|
||||
- [x] 3.3 Verify WeChat, Alipay, and wallet result handling remains unchanged after routing-policy updates.
|
||||
- [x] 3.4 Verify API error codes/messages are passed through according to the interface documentation.
|
||||
Reference in New Issue
Block a user