feat: wave 2 migration (P3, P5, P7 openspec changes)

Implements, verifies, and archives the three remaining Wave 2 changes from
openspec/MIGRATION-PLAN.md.

- add-wallet-settlement (P3): demo recharge, guarded withdrawal freeze and
  one-time admin review, paginated own fund entries, idempotent per-shop
  weekly/monthly settlement statements with commission rate and one-time
  payout confirmation.
- add-merchant-onboarding (P5): personal/enterprise applications with one live
  application per user, guarded review with mandatory rejection reason, and
  transactional shop + owner provisioning returning one-time credentials;
  mall onboarding/status pages and an admin review console.
- add-membership-messaging (P7): platform member levels, append-only growth
  accrual on order completion with guarded one-way leveling, order/shipment/
  refund system messages with unread/read state and soft deletion, plus the
  mall header unread badge.

Backend: migrations 0019-0023, new wallet, settlement, merchant_onboarding,
membership and messaging modules, event hooks in order/fulfillment/aftersale,
and integration suites for each. Shared contract extended and all three
frontends updated; code indexes, domain docs, backend guidelines and the
migration tracker synced.

Verification: cargo test -p vmall-api green twice consecutively; mall, admin
and shop-admin builds pass; browser smoke on every new surface; openspec
validate --all --strict green (33 passed).

The three changes share the @vmall/shared contract, the mall mock adapter and
per-app locale/nav files, so they are committed together to keep every commit
buildable.
This commit is contained in:
2026-09-25 15:25:29 +00:00
parent 772aafa3fb
commit 9904696e76
120 changed files with 14097 additions and 125 deletions
@@ -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