docs(openspec): propose 8 tigshop migration changes (P0-P7) + migration plan
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Withdrawal review and commission configuration
|
||||
The platform console SHALL list withdrawal applications and approve or reject each pending application through the shared API contract, surfacing review outcomes and conflicts (409 on a repeated review) without silent failure. It SHALL expose the platform commission rate as an integer basis-point setting that admins can read and update.
|
||||
|
||||
#### Scenario: reject returns funds
|
||||
- **WHEN** an admin rejects a pending withdrawal application
|
||||
- **THEN** the console shows the rejected status and the buyer's wallet reflects the amount back in available balance
|
||||
|
||||
#### Scenario: approve deducts frozen funds
|
||||
- **WHEN** an admin approves a pending withdrawal application
|
||||
- **THEN** the console shows the approved status and the frozen balance decreases by the requested amount
|
||||
|
||||
#### Scenario: set commission rate
|
||||
- **WHEN** an admin updates the commission rate
|
||||
- **THEN** settlement statements generated afterwards snapshot the new rate
|
||||
|
||||
### Requirement: Settlement statement confirmation
|
||||
The platform console SHALL list settlement statements across shops with their amount snapshots and statuses, allow manual generation for a shop and closed period, and confirm payout exactly once per statement through the shared API contract, surfacing a 409 on repeated confirmation.
|
||||
|
||||
#### Scenario: confirm payout
|
||||
- **WHEN** an admin confirms a pending statement
|
||||
- **THEN** the console shows the statement confirmed and the shop owner's ledger records the payout
|
||||
|
||||
#### Scenario: manual generation is idempotent
|
||||
- **WHEN** an admin generates a statement for a shop and period that already has one
|
||||
- **THEN** the existing statement is shown and no duplicate is created
|
||||
@@ -0,0 +1,20 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Buyer wallet surface
|
||||
The mall SHALL render a buyer-center wallet page driven by the selected API adapter through `@vmall/shared`: available and frozen balance with currency, paginated fund entries, a clearly labeled demo recharge form, and a withdrawal request form. Balances and entries SHALL reflect backend state after each action rather than local-only state. The wallet SHALL be a mall API domain with fixed-adapter fallback methods and `LIVE_PICKS` wiring following the established per-domain adapter pattern.
|
||||
|
||||
#### Scenario: wallet page loads live state
|
||||
- **WHEN** a signed-in buyer opens the wallet page
|
||||
- **THEN** balances and the first page of fund entries render from the shared wallet contract
|
||||
|
||||
#### Scenario: demo recharge updates balance
|
||||
- **WHEN** the buyer submits a demo recharge
|
||||
- **THEN** the visible available balance reflects the credit without a reload and the form is visibly marked simulated
|
||||
|
||||
#### Scenario: withdrawal freezes visibly
|
||||
- **WHEN** the buyer submits a withdrawal request
|
||||
- **THEN** the visible summary shows available decreased and frozen increased by the requested amount, and the request appears in the withdrawal list as pending
|
||||
|
||||
#### Scenario: fixed adapter remains functional
|
||||
- **WHEN** the wallet domain is configured to fixed data
|
||||
- **THEN** the wallet page behaves deterministically through the same shared client methods
|
||||
@@ -0,0 +1,23 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Merchant settlement statements
|
||||
Shop-admin SHALL list and open the signed-in shop's settlement statements — period, amount snapshot, and status — through the shared API contract, and allow manual generation for a closed period of the own shop. Shop-scoped pages SHALL never expose another shop's statements or their order/refund breakdown.
|
||||
|
||||
#### Scenario: statements list and detail
|
||||
- **WHEN** a merchant opens the settlement page
|
||||
- **THEN** only their own shop's statements are listed and each opens into its snapshot breakdown of orders, refunds, commission, and payable amount
|
||||
|
||||
#### Scenario: generation is idempotent in the UI
|
||||
- **WHEN** the merchant generates a statement for a period that already has one
|
||||
- **THEN** the existing statement appears without duplication
|
||||
|
||||
### Requirement: Shop-account withdrawal
|
||||
The shop owner SHALL view the shop account summary (available and frozen balance of the shop owner's account) and apply to withdraw from it through the shared API contract, seeing the request as pending until the platform reviews it.
|
||||
|
||||
#### Scenario: shop-account withdrawal freezes funds
|
||||
- **WHEN** the shop owner submits a withdrawal request from the shop-account page
|
||||
- **THEN** the summary reflects the frozen amount and the request lists as pending
|
||||
|
||||
#### Scenario: reviewed request reflects outcome
|
||||
- **WHEN** the platform rejects the shop owner's pending withdrawal
|
||||
- **THEN** the shop-account summary shows the amount returned to available balance and the request shows as rejected
|
||||
@@ -0,0 +1,56 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Idempotent periodic statement generation
|
||||
A settlement statement SHALL be generated manually for one shop, one period kind (week or month), and one closed period. For the same shop, period kind, and period start at most one statement SHALL exist, enforced by the database. A repeated generation request SHALL return the existing statement unchanged instead of recomputing or duplicating it. No scheduled batch job SHALL generate statements.
|
||||
|
||||
#### Scenario: repeat generation is idempotent
|
||||
- **WHEN** a statement already exists for a shop and period and generation is requested again
|
||||
- **THEN** the existing statement is returned unchanged and no second row is created
|
||||
|
||||
#### Scenario: generation is manual only
|
||||
- **WHEN** no generation request is made for a closed period
|
||||
- **THEN** no statement exists for that period
|
||||
|
||||
### Requirement: Immutable amount snapshot
|
||||
A generated statement SHALL snapshot the contributing order count, the gross total of confirmed-received orders in the period, the deduction total of completed refunds against those orders (`aftersales` rows with status `refunded`, per-order totals from `add-aftersale-refunds`), the platform commission rate at generation time, the commission amount, and the payable amount where payable = gross − refunds − commission. All amounts SHALL be integer minor units computed with integer arithmetic, and the commission rate SHALL be an integer basis-point value. The snapshot SHALL NOT change after generation even when later orders, refunds, or commission-rate changes occur.
|
||||
|
||||
#### Scenario: refunds reduce the payable amount
|
||||
- **WHEN** a confirmed-received order in the period has a completed refund of 2000 minor units
|
||||
- **THEN** the statement's refund deduction includes those 2000 minor units and the payable amount is reduced accordingly
|
||||
|
||||
#### Scenario: commission arithmetic is integral
|
||||
- **WHEN** the commission rate is 500 basis points and gross minus refunds is 10000 minor units
|
||||
- **THEN** the commission snapshot is 500 minor units and the payable snapshot is 9500 minor units with no floating-point arithmetic
|
||||
|
||||
#### Scenario: snapshot survives rate changes
|
||||
- **WHEN** the platform commission rate changes after a statement was generated
|
||||
- **THEN** the generated statement keeps its snapshotted rate and amounts
|
||||
|
||||
### Requirement: Platform commission rate configuration
|
||||
The commission rate SHALL be a single platform-level setting stored as integer basis points and readable and editable by platform admins. A rate change SHALL affect only statements generated after the change.
|
||||
|
||||
#### Scenario: new rate applies to new statements
|
||||
- **WHEN** an admin sets the commission rate and a statement is generated afterwards
|
||||
- **THEN** that statement snapshots the new rate
|
||||
|
||||
### Requirement: One-time payout confirmation
|
||||
A statement SHALL transition exactly once from `pending` to `confirmed` through a guarded status transition requiring the `pending` status, triggered by a platform admin confirming the payout; a repeated confirmation SHALL return 409. Confirmation SHALL record the confirming admin and timestamp and SHALL credit the payable amount to the shop owner's available account with exactly one ledger entry referencing the statement.
|
||||
|
||||
#### Scenario: confirm pays out once
|
||||
- **WHEN** an admin confirms a pending statement
|
||||
- **THEN** the statement becomes confirmed and the shop owner's available balance increases by the payable amount with one ledger entry referencing the statement
|
||||
|
||||
#### Scenario: double confirmation conflicts
|
||||
- **WHEN** an admin confirms an already confirmed statement
|
||||
- **THEN** the API returns 409 and no second ledger entry is written
|
||||
|
||||
### Requirement: Shop-scoped statement visibility
|
||||
Statements and their breakdown SHALL be scoped to one shop. Through the shop's own-shop scope, shop users SHALL read and generate statements only for their own shop and SHALL never observe another shop's statements, contributing orders, or refund lines; platform admins SHALL observe every shop.
|
||||
|
||||
#### Scenario: merchant sees own shop only
|
||||
- **WHEN** a shop user lists settlement statements
|
||||
- **THEN** only statements of their own shop appear
|
||||
|
||||
#### Scenario: detail breakdown is shop-scoped
|
||||
- **WHEN** a shop user opens a statement detail
|
||||
- **THEN** the contributing orders and refunded amounts are visible for that shop only
|
||||
@@ -0,0 +1,49 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Demo wallet recharge
|
||||
An authenticated user SHALL recharge their wallet through a simulated demo flow that records a wallet recharge row and credits the available monetary account with one signed ledger entry in one transaction, without invoking any external payment channel. The API payload and the wallet UI SHALL clearly label the recharge as simulated/demo. Amounts SHALL be positive integer minor units in the account's currency, and monetary arithmetic SHALL NOT use floating point.
|
||||
|
||||
#### Scenario: demo recharge credits balance
|
||||
- **WHEN** a signed-in buyer submits a demo recharge of 5000 minor units
|
||||
- **THEN** the available balance increases by exactly 5000 minor units and exactly one ledger entry with reason `wallet_recharge` records the resulting balance
|
||||
|
||||
#### Scenario: flow is labeled as demo
|
||||
- **WHEN** a buyer opens the recharge flow
|
||||
- **THEN** it is visibly marked as a simulated recharge and no external payment provider is contacted
|
||||
|
||||
### Requirement: Guarded withdrawal freeze
|
||||
An authenticated user SHALL apply to withdraw a positive amount in their account currency. The application SHALL atomically move the amount from available to frozen balance through guarded conditional updates that succeed only when available balance covers the amount, and each balance change SHALL be paired with a ledger entry in the same transaction. When available balance is insufficient the request SHALL fail without changing any balance, and concurrent applications SHALL never overdraw or produce a negative balance.
|
||||
|
||||
#### Scenario: withdrawal freezes funds
|
||||
- **WHEN** a buyer applies to withdraw 1000 minor units
|
||||
- **THEN** available balance decreases and frozen balance increases by exactly 1000 minor units and two ledger entries record the move
|
||||
|
||||
#### Scenario: concurrent applications cannot overdraw
|
||||
- **WHEN** two withdrawal applications together exceed the available balance
|
||||
- **THEN** at most one application succeeds and all balances remain non-negative
|
||||
|
||||
### Requirement: One-time withdrawal review
|
||||
Platform admins SHALL list pending withdrawal applications and approve or reject each exactly once through a guarded status transition that requires the `pending` status and returns 409 on a repeated review. Approve SHALL deduct the frozen amount with a ledger entry recording that the funds left the platform. Reject SHALL return the frozen amount to available balance with a ledger entry. Every review SHALL record the reviewing admin, timestamp, and optional note.
|
||||
|
||||
#### Scenario: reject returns funds
|
||||
- **WHEN** an admin rejects a pending withdrawal application
|
||||
- **THEN** the frozen amount returns to available balance and the application status becomes rejected
|
||||
|
||||
#### Scenario: approve consumes frozen funds
|
||||
- **WHEN** an admin approves a pending withdrawal application
|
||||
- **THEN** frozen balance decreases by the requested amount and the application status becomes approved
|
||||
|
||||
#### Scenario: repeated review conflicts
|
||||
- **WHEN** an admin reviews an application that was already reviewed
|
||||
- **THEN** the API returns 409 and no balance or ledger row changes
|
||||
|
||||
### Requirement: Paginated fund entries
|
||||
An authenticated user SHALL page through their own monetary account entries newest first. Each entry SHALL carry the signed delta minor, resulting balance minor, reason, optional business reference, and timestamp, mapped from the existing append-only ledger rows. Entries SHALL never expose or mutate another user's ledger.
|
||||
|
||||
#### Scenario: entries page maps the ledger
|
||||
- **WHEN** the buyer requests a page of fund entries
|
||||
- **THEN** only their own available/frozen ledger rows appear with signed deltas and resulting balances
|
||||
|
||||
#### Scenario: entries are user-isolated
|
||||
- **WHEN** one user requests fund entries
|
||||
- **THEN** no entry belonging to another user is ever returned
|
||||
Reference in New Issue
Block a user