docs(openspec): propose 8 tigshop migration changes (P0-P7) + migration plan
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Member level management
|
||||
Platform admins SHALL manage member levels from a dedicated admin console page through the shared API contract: levels listed in growth-threshold order, and create, edit, and delete actions over name, icon, growth threshold, and benefits with both locales editable. Deleting a level in use SHALL surface the API rejection instead of silently succeeding, and member-level management SHALL be reachable from the authenticated console navigation beside existing platform operations.
|
||||
|
||||
#### Scenario: manage a member level
|
||||
- **WHEN** a platform admin creates a level with bilingual name and benefits, an icon, and a growth threshold
|
||||
- **THEN** it appears in threshold order and is available for automatic leveling
|
||||
|
||||
#### Scenario: edit a growth threshold
|
||||
- **WHEN** a platform admin changes a level's growth threshold to a unique value
|
||||
- **THEN** the level persists with the new threshold and the bilingual content unchanged
|
||||
|
||||
#### Scenario: deleting a level in use fails visibly
|
||||
- **WHEN** a platform admin deletes a level that customers hold
|
||||
- **THEN** the console surfaces the rejection and the level and its members remain unchanged
|
||||
|
||||
#### Scenario: level management appears in admin navigation
|
||||
- **WHEN** an authenticated platform admin opens the admin console
|
||||
- **THEN** member-level management is reachable from the console nav
|
||||
@@ -0,0 +1,46 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Member center level page
|
||||
The buyer center SHALL render a membership level page from the selected API adapter: the current level's name, icon, and benefits, the total growth value, progress toward the next level's threshold, and the customer's growth history from the growth ledger. The page SHALL NOT derive level state from fixtures or local state, and it SHALL behave deterministically when the `membership` domain is configured to fixed data.
|
||||
|
||||
#### Scenario: level page reflects backend state
|
||||
- **WHEN** a signed-in shopper whose growth qualifies for a level opens the member-center level page
|
||||
- **THEN** the current level, benefits, growth total, and remaining growth to the next level render from the adapter without per-entry requests
|
||||
|
||||
#### Scenario: growth history lists ledger entries
|
||||
- **WHEN** a shopper opens the level page
|
||||
- **THEN** recent growth ledger entries with delta, reason, and time render paginated from the adapter
|
||||
|
||||
#### Scenario: fixed adapter remains functional
|
||||
- **WHEN** the `membership` domain is configured to fixed data
|
||||
- **THEN** the level page renders deterministic fixed level and growth data through the same shared client methods
|
||||
|
||||
### Requirement: Message center
|
||||
The mall SHALL render a user message center from the selected API adapter with a paginated message list and an unread-only filter. Opening or explicitly marking a message read, marking all read, and deleting a message SHALL persist through the API and update the visible list and counts without local-only mutation. Each message SHALL render its title and body in the active locale from the shared bilingual contract. Listing and refresh SHALL happen on entry and on demand; no push transport is required.
|
||||
|
||||
#### Scenario: unread filter and marking
|
||||
- **WHEN** a shopper filters the message center to unread and marks one message read
|
||||
- **THEN** the message persists as read and leaves the unread-only view with the unread count reduced
|
||||
|
||||
#### Scenario: mark all read
|
||||
- **WHEN** a shopper uses mark-all-read in the message center
|
||||
- **THEN** every unread message becomes read and the unread-only view empties
|
||||
|
||||
#### Scenario: delete a message
|
||||
- **WHEN** a shopper deletes a message
|
||||
- **THEN** it disappears from the list and the unread count through the API state
|
||||
|
||||
#### Scenario: fixed adapter remains functional
|
||||
- **WHEN** the `messaging` domain is configured to fixed data
|
||||
- **THEN** message listing, read marking, mark-all-read, and deletion behave deterministically through the same shared client methods
|
||||
|
||||
### Requirement: Top-bar unread badge
|
||||
The mall shell SHALL show the authenticated customer's unread message count as a badge on its message entry, read from the shared unread-count contract. The badge SHALL refresh on page entry and after read, mark-all-read, and delete actions, and SHALL be absent for anonymous shoppers.
|
||||
|
||||
#### Scenario: badge reflects unread count
|
||||
- **WHEN** a signed-in shopper with three unread messages loads any mall page
|
||||
- **THEN** the message entry badge shows three
|
||||
|
||||
#### Scenario: badge clears after mark-all-read
|
||||
- **WHEN** a shopper marks all messages read and returns to the shell
|
||||
- **THEN** the badge shows no unread count
|
||||
@@ -0,0 +1,61 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Member level catalog
|
||||
The platform SHALL manage member levels through admin-only APIs. Each level SHALL carry a bilingual name (`{en, zh}`), an icon key, an integer growth-value threshold, and a bilingual benefits description (`{en, zh}`). Growth thresholds SHALL be unique across levels, and the effective ordering of levels SHALL follow the threshold. Deleting a level that any customer currently holds SHALL be rejected instead of reassigning or orphaning members.
|
||||
|
||||
#### Scenario: create a level
|
||||
- **WHEN** a platform admin creates a level with name, icon, growth threshold, and benefits in both locales
|
||||
- **THEN** the level is listed with its bilingual content and threshold ordering
|
||||
|
||||
#### Scenario: duplicate threshold is rejected
|
||||
- **WHEN** a platform admin creates or edits a level to reuse another level's growth threshold
|
||||
- **THEN** the request is rejected and the existing levels are unchanged
|
||||
|
||||
#### Scenario: deleting a level in use is rejected
|
||||
- **WHEN** a platform admin deletes a level that at least one customer holds
|
||||
- **THEN** the request is rejected and no customer's level changes
|
||||
|
||||
### Requirement: Growth value accrual ledger
|
||||
When a customer confirms receipt and an order reaches completed, the customer SHALL earn growth value equal to that order's realized paid amount converted to the base currency and truncated to whole units through integer minor-unit arithmetic using the base currency exponent, with no floating-point computation. Accrual SHALL append exactly one entry per order to a growth ledger that, like the points ledger, is append-only and records the delta, running growth total, reason, and order reference. Retried or repeated completion events SHALL NOT create a second entry or a second accrual.
|
||||
|
||||
#### Scenario: confirm receipt accrues growth
|
||||
- **WHEN** a customer confirms receipt of an order whose realized paid amount converts to 120 whole base-currency units
|
||||
- **THEN** the growth ledger gains one entry with delta 120 referencing that order and the customer's growth total rises by 120
|
||||
|
||||
#### Scenario: repeated completion is idempotent
|
||||
- **WHEN** the completion handling for the same order runs again
|
||||
- **THEN** no second ledger entry exists and the growth total is unchanged
|
||||
|
||||
#### Scenario: ledger entries are immutable
|
||||
- **WHEN** any code path handles growth after an entry was written
|
||||
- **THEN** the entry is only ever appended to, never updated or deleted
|
||||
|
||||
### Requirement: Automatic level upgrade
|
||||
Inside the growth accrual transaction, the customer's level SHALL be re-derived as the level with the highest growth threshold less than or equal to the customer's growth total and written to `users.level` with a guarded update. Leveling SHALL be one-way: a customer is only ever moved to a level with a strictly higher threshold than the current one, and never demoted automatically. A growth total exactly at a threshold qualifies for that level, and when several thresholds are passed the highest qualifying level wins. A customer below every threshold SHALL hold no level.
|
||||
|
||||
#### Scenario: growth at the threshold upgrades
|
||||
- **WHEN** an accrual brings a customer's growth total exactly to a level's threshold
|
||||
- **THEN** the customer's level becomes that level in the same transaction as the ledger entry
|
||||
|
||||
#### Scenario: jumping past intermediate levels
|
||||
- **WHEN** an accrual passes two levels' thresholds at once
|
||||
- **THEN** the customer holds the highest qualifying level, not the intermediate one
|
||||
|
||||
#### Scenario: no level below every threshold
|
||||
- **WHEN** a customer's growth total is below the lowest defined threshold
|
||||
- **THEN** the customer holds no level and a later qualifying accrual assigns one
|
||||
|
||||
### Requirement: Level benefits display
|
||||
An authenticated customer SHALL read their own membership status: current level with name, icon, and benefits, total growth value, the next level's threshold and remaining growth to reach it, and a paginated view of their own growth ledger. The status SHALL re-derive the displayed level against current thresholds, and one customer SHALL never read another customer's growth history.
|
||||
|
||||
#### Scenario: progress to the next level
|
||||
- **WHEN** a customer between two thresholds opens their membership status
|
||||
- **THEN** the response shows the current level's benefits and the exact growth remaining to the next level
|
||||
|
||||
#### Scenario: top level has no next level
|
||||
- **WHEN** a customer at or above the highest threshold reads their membership status
|
||||
- **THEN** the response contains no next level and no remaining growth target
|
||||
|
||||
#### Scenario: growth history is own-only
|
||||
- **WHEN** a customer requests their growth ledger
|
||||
- **THEN** only entries of the authenticated customer are returned, newest first and paginated
|
||||
@@ -0,0 +1,50 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: System event messages
|
||||
An order payment success, a shipment dispatch, and a refund completion (including after-sale refunds) SHALL each create one system message for the customer who owns the order. Each message SHALL record its kind, a bilingual title and body (`{en, zh}`) naming the affected order, and the order (and refund) reference it was triggered by. Emission SHALL be idempotent per customer, kind, and reference, so re-running an event handler never writes a duplicate message.
|
||||
|
||||
#### Scenario: paying an order notifies the customer
|
||||
- **WHEN** a customer's order payment succeeds
|
||||
- **THEN** an `order_paid` message referencing that order appears in the customer's inbox
|
||||
|
||||
#### Scenario: dispatch notifies the customer
|
||||
- **WHEN** a shop marks a shipment of the customer's order as shipped
|
||||
- **THEN** an `order_shipped` message referencing that order appears in the customer's inbox
|
||||
|
||||
#### Scenario: refund completion notifies the customer
|
||||
- **WHEN** a refund for the customer's order completes
|
||||
- **THEN** a `refund_completed` message referencing that order and refund appears in the customer's inbox
|
||||
|
||||
#### Scenario: re-run event handler does not duplicate
|
||||
- **WHEN** the same event handler for the same order, kind, and reference runs twice
|
||||
- **THEN** exactly one message exists for that customer, kind, and reference
|
||||
|
||||
### Requirement: User message state machine
|
||||
A message SHALL belong to exactly one customer and move through `unread` and `read` states plus a soft deletion. Messages are created `unread`; marking one read or all read SHALL use a guarded update that touches only `unread` rows, so repeated marking never rewrites already-read rows. Deletion SHALL set a soft-delete marker rather than removing the row, SHALL be idempotent, and SHALL make the message invisible to listing and counting. Customers SHALL only ever read, mark, or delete their own messages.
|
||||
|
||||
#### Scenario: mark one message read
|
||||
- **WHEN** a customer marks their unread message read twice
|
||||
- **THEN** the message is read and only the first call changed its state
|
||||
|
||||
#### Scenario: mark all read touches only unread
|
||||
- **WHEN** a customer with three unread and two read messages marks all read
|
||||
- **THEN** exactly the three unread rows become read and the two read rows are untouched
|
||||
|
||||
#### Scenario: deleted messages disappear
|
||||
- **WHEN** a customer deletes a message
|
||||
- **THEN** it is absent from their list and unread count while its row remains for audit
|
||||
|
||||
#### Scenario: foreign messages are unreachable
|
||||
- **WHEN** a customer addresses another customer's message for read or delete
|
||||
- **THEN** the request fails without changing that message
|
||||
|
||||
### Requirement: Unread count endpoint
|
||||
An authenticated customer SHALL read their unread message count through a dedicated endpoint that excludes soft-deleted messages. The count SHALL reflect read, mark-all-read, and delete actions immediately and SHALL only ever count the requesting customer's messages.
|
||||
|
||||
#### Scenario: count drops after mark-all-read
|
||||
- **WHEN** a customer with four unread messages marks all read
|
||||
- **THEN** the unread count endpoint returns zero
|
||||
|
||||
#### Scenario: deleting an unread message drops the count
|
||||
- **WHEN** a customer deletes one of three unread messages
|
||||
- **THEN** the unread count endpoint returns two
|
||||
Reference in New Issue
Block a user