docs(openspec): plan shop coupons, accounts, points, flash sales, and group buying
Capture exclusive promotion composition, empty-group cancel, and mall surface scope so the five marketing changes can be implemented without stacking or lifecycle ambiguity. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
e10cae5789
commit
53548196f8
@@ -0,0 +1,16 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Live shop coupon surfaces
|
||||
The mall SHALL load a product's currently claimable shop coupons and the signed-in customer's coupon list through the shared API client, replacing direct coupon fixtures. Checkout SHALL present eligible owned coupons separately for each shop order and show the server-returned discount after submission. Payment and order-detail views SHALL show the persisted `discount_minor` and post-discount total from the order payload.
|
||||
|
||||
#### Scenario: claim from a product page
|
||||
- **WHEN** a signed-in shopper claims an active coupon with remaining stock from a product page
|
||||
- **THEN** it appears in the shopper's coupon list without a fixture import
|
||||
|
||||
#### Scenario: select coupon by shop
|
||||
- **WHEN** a cart spans two shops and the shopper selects a coupon for one shop
|
||||
- **THEN** checkout submits the choice only for that shop and the other shop remains undiscounted
|
||||
|
||||
#### Scenario: order shows realized discount
|
||||
- **WHEN** checkout succeeds with a coupon on one shop order
|
||||
- **THEN** that order's payment and detail views show the server discount and reduced total without a client-calculated amount
|
||||
@@ -0,0 +1,12 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Merchant coupon management
|
||||
Shop users SHALL manage only their shop's coupon templates from shop-admin, including localized title, amount and threshold in minor units, currency, claim stock, active window, and enabled state. Shop-admin SHALL expose a coupons navigation entry beside existing shop operations.
|
||||
|
||||
#### Scenario: create an active template
|
||||
- **WHEN** a shop owner creates a valid coupon template
|
||||
- **THEN** the template is available for eligible customers to claim during its active window
|
||||
|
||||
#### Scenario: coupons appear in shop navigation
|
||||
- **WHEN** an authenticated shop user opens shop-admin
|
||||
- **THEN** a coupons management entry is reachable without leaving the shop-scoped console
|
||||
@@ -0,0 +1,31 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Checkout splits by shop
|
||||
`POST /api/orders/checkout` SHALL create one order per distinct shop in the cart, in a single database transaction: stock decrement, order + item insert with price snapshots, cart clear, and requested coupon redemption. All amounts use the cart's SKU currencies converted into the buyer-chosen display currency at checkout time. The request MAY select at most one owned coupon per generated shop order; the server SHALL validate its ownership, shop, status, validity window, threshold, and converted amount, then persist `coupon_id`, `discount_minor`, and the post-discount `total_minor`. The client SHALL NOT provide a discount amount. This requirement does not define activity prices; a later flash-sale or group-buying change that rewrites checkout SHALL restate these coupon clauses and SHALL reject a coupon on any shop order that applied an activity price.
|
||||
|
||||
#### Scenario: two shops → two orders
|
||||
- **WHEN** the cart contains SKUs from shops A and B
|
||||
- **THEN** two orders are created, each with only its shop's items, and the cart is empty
|
||||
|
||||
#### Scenario: insufficient stock
|
||||
- **WHEN** any line's qty exceeds SKU stock
|
||||
- **THEN** the whole checkout returns 409 and no order is created and stock is unchanged
|
||||
|
||||
#### Scenario: coupon applies to one matching shop
|
||||
- **WHEN** the customer selects an eligible coupon issued by shop A for a cart containing shops A and B
|
||||
- **THEN** only shop A's order records that coupon and its server-calculated discount
|
||||
|
||||
### Requirement: Order lifecycle
|
||||
Status transitions SHALL be: pending_payment → paid → fulfilling → shipped → completed; cancellable only from pending_payment, which MUST restore stock and restore a redeemed coupon to claimed status when the order has one.
|
||||
|
||||
#### Scenario: cancel restores stock
|
||||
- **WHEN** a customer cancels a pending_payment order
|
||||
- **THEN** stock of each SKU increases by the ordered qty and status is cancelled
|
||||
|
||||
#### Scenario: cancel restores coupon
|
||||
- **WHEN** a customer cancels a pending_payment order with a redeemed coupon
|
||||
- **THEN** the coupon is detached from the order and becomes claimed
|
||||
|
||||
#### Scenario: illegal transition rejected
|
||||
- **WHEN** cancelling a paid order via the customer endpoint
|
||||
- **THEN** the API returns 409
|
||||
@@ -0,0 +1,22 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Shop coupon template management
|
||||
A shop_owner or shop_staff SHALL create, list, update, disable, and delete only that shop's coupon templates. A template SHALL contain localized title, fixed `amount_minor`, `threshold_minor`, enabled ISO currency, non-negative claim stock, and an inclusive active window; amount MUST be positive and threshold MUST NOT be negative.
|
||||
|
||||
#### Scenario: cross-shop template is hidden
|
||||
- **WHEN** a shop user requests or mutates another shop's coupon template
|
||||
- **THEN** the API returns 404
|
||||
|
||||
### Requirement: Customer coupon claim and listing
|
||||
An authenticated customer SHALL list owned coupons and claim an active template at most once. Claiming SHALL atomically create a user-held snapshot and decrement claim stock only when stock remains; listing SHALL distinguish claimed, redeemed, and expired coupons.
|
||||
|
||||
#### Scenario: concurrent final claim
|
||||
- **WHEN** two customers claim the final remaining template instance concurrently
|
||||
- **THEN** exactly one claim succeeds and the other receives 409
|
||||
|
||||
### Requirement: Coupon redemption lifecycle
|
||||
A claimed coupon SHALL be redeemable only by its owner, for its issuing shop, within its snapshot window, and when the shop-order subtotal reaches its snapshot threshold. Redemption SHALL bind the coupon to one order; cancellation of that pending-payment order SHALL restore it to claimed. Later activity-priced shop orders (flash sale or group buy) SHALL NOT redeem a coupon; those changes restated this exclusion on checkout.
|
||||
|
||||
#### Scenario: cancelled order restores coupon
|
||||
- **WHEN** a customer cancels a pending-payment order redeemed with a coupon
|
||||
- **THEN** the coupon again has claimed status and no order binding
|
||||
Reference in New Issue
Block a user