docs(openspec): propose 8 tigshop migration changes (P0-P7) + migration plan

This commit is contained in:
Chengdong Zhang
2026-09-23 13:30:36 +08:00
parent 0d0e10b97b
commit 9a749e2551
47 changed files with 1607 additions and 0 deletions
@@ -0,0 +1,30 @@
## Why
Product detail still renders display-only comment fixtures and deliberately offers no reviews tab because no review model exists. Reviews are mall trust infrastructure: shoppers decide from real buyer feedback on real purchases and merchants answer it publicly, so the placeholder must be replaced by reviews backed by completed order lines instead of invented reviewers.
## What Changes
- Add buyer reviews for product lines of completed (received) orders: a 1-5 star rating, text, and optional image URLs, at most one review per order line enforced by a unique index plus creation preconditions.
- Let the owning merchant reply to a review exactly once and let platform admins hide (soft delete) or delete reviews as moderation.
- Add product review listing with pagination over visible reviews only and a SQL-aggregated rating summary (average, count, and star distribution).
- Replace the mall product-detail display-only comment placeholder with the real review area and add a buyer-center "pending review" entry with a review submission form.
- Add a shop-admin review list/reply page and an admin review moderation list over the shared contract.
- Keep equivalent fixed-adapter review behavior as the rollback implementation.
## Capabilities
### New Capabilities
- `reviews`: One review per completed order line, a single merchant reply per review, platform hide/delete moderation, visible-only public listing, and SQL rating aggregation.
### Modified Capabilities
- `frontend-mall`: Product detail renders the real review area with summary and paginated visible reviews, and the buyer center gains pending-review discovery and review submission.
- `frontend-shop-admin`: Merchants list their own shop's reviews and reply once per review.
- `frontend-admin`: Platform admins moderate reviews with hide and delete actions.
## Non-goals
Follow-up reviews (追评), review ranking or sorting algorithms, photo-reward points (left to P7), anonymous reviews, video reviews, review editing or withdrawal, and merchant review analytics are excluded.
## Impact
Adds one Postgres migration (`product_reviews`), a Rust review module with customer, `own_shop`-scoped merchant, and admin routes, shared types and API methods, a Mall `reviews` domain pick with fixed-adapter parity, and Mall product-detail plus buyer-center updates alongside new shop-admin and admin console pages.
@@ -0,0 +1,16 @@
## ADDED Requirements
### Requirement: Platform review moderation
Platform admins SHALL review a paginated moderation list of all reviews with their product, customer, and shop context and SHALL hide or delete reviews through the shared API contract. Admin SHALL expose review moderation navigation beside existing platform operations.
#### Scenario: hide a review from the moderation list
- **WHEN** a platform admin hides a review
- **THEN** the list shows it as hidden and the review leaves the mall storefront and rating summary
#### Scenario: delete a review
- **WHEN** a platform admin deletes a review
- **THEN** the row is removed and absent from both admin and storefront listings
#### Scenario: moderation appears in admin navigation
- **WHEN** an authenticated platform admin opens the admin console
- **THEN** a review moderation entry is reachable from the console nav
@@ -0,0 +1,27 @@
## ADDED Requirements
### Requirement: Live product review area
The mall SHALL render product reviews from the shared selected API adapter instead of display-only comment fixtures. Product detail SHALL show the rating summary (average, count, star distribution) and a paginated list of visible reviews with images and merchant replies, with totals from the API and no invented reviewers or ratings.
#### Scenario: detail page shows real reviews
- **WHEN** a shopper opens a product whose reviews were posted through completed orders
- **THEN** the review area shows the aggregated summary and those reviews with their merchant replies
#### Scenario: detail page without reviews
- **WHEN** a shopper opens a product with no visible reviews
- **THEN** the review area shows an empty state and a zeroed summary instead of fixture comments
### Requirement: Buyer-center pending review and submission
The buyer center SHALL expose a "pending review" entry counting completed order lines awaiting review and a submission form posting rating, text, and optional image URLs through the shared API contract. Submission SHALL require the customer's own unreviewed completed order line, and the pending list SHALL refresh after a successful submission.
#### Scenario: submit a review from the buyer center
- **WHEN** a shopper submits a review for a pending order line and it succeeds
- **THEN** the pending list and count drop that line and the review appears on the product detail page
#### Scenario: anonymous submission requires sign-in
- **WHEN** a signed-out shopper opens the pending review entry or submission form
- **THEN** the mall sends the shopper to sign in with the current URL as the return destination
#### Scenario: fixed adapter remains functional
- **WHEN** the reviews domain is configured to fixed data
- **THEN** the review area, pending-review entry, and submission flows behave deterministically through the same shared client methods
@@ -0,0 +1,12 @@
## ADDED Requirements
### Requirement: Merchant review management
Shop users SHALL list only their own shop's reviews in shop-admin through the shared API contract, with pagination and visible reply state, and SHALL submit at most one reply per review. Shop-admin SHALL expose a review management entry beside existing shop operations.
#### Scenario: reply to a review
- **WHEN** a merchant opens an unreplied review of their shop and submits a reply
- **THEN** the reply is stored once and the review row shows it as replied
#### Scenario: already replied review offers no second reply
- **WHEN** a merchant opens a review that already carries their shop's reply
- **THEN** no reply submission is offered and other shops' reviews are unreachable
@@ -0,0 +1,67 @@
## ADDED Requirements
### Requirement: One review per completed order line
A signed-in customer SHALL create a review only for a product line of their own completed (received) order that has not been reviewed yet. A review SHALL carry a 1-5 star rating, text content, and optional image URLs, and the rating and content snapshot SHALL never change after creation. The database SHALL enforce at most one review per order line through a unique index on the order line, and creation SHALL validate the order-line precondition before insert.
#### Scenario: review a completed order line
- **WHEN** a customer reviews a product line of their own completed order
- **THEN** the review is created with the submitted rating, text, and image URLs and the line can no longer be reviewed
#### Scenario: second review of the same line is rejected
- **WHEN** a customer submits a second review for an already reviewed order line
- **THEN** the request is rejected and exactly one review row exists for that line
#### Scenario: unreviewable line is rejected
- **WHEN** a customer reviews a line from another customer's order or from an order that is not completed
- **THEN** the request is rejected without creating a review
### Requirement: Bilingual review content shape
Review content and merchant replies SHALL be stored as `{en, zh}` localized JSONB content. A submission MAY populate only the shopper's or merchant's active locale, and every display SHALL fall back to the other locale when the active locale is empty.
#### Scenario: single-locale submission renders everywhere
- **WHEN** a shopper submits review text in only one locale
- **THEN** both mall locales display the review through the non-empty locale fallback
### Requirement: Single merchant reply per review
Only a shop user of the review's own shop SHALL reply to a review, at most once. The reply SHALL be written with a guarded update that succeeds only while no reply exists, and a second or cross-shop reply attempt SHALL be rejected.
#### Scenario: first reply succeeds
- **WHEN** a merchant of the reviewed product's shop replies to a review
- **THEN** the reply is stored with its audit timestamp and appears with the review
#### Scenario: second reply is rejected
- **WHEN** the same merchant submits another reply to a review that already has one
- **THEN** the request is rejected and the existing reply is unchanged
### Requirement: Platform moderation hides or deletes reviews
Platform admins SHALL hide or delete any review. Hiding SHALL be a soft delete recorded through a guarded status transition that validates the prior visible state, and deletion SHALL remove the row. Hidden and deleted reviews SHALL be absent from storefront listings and rating summaries, while admin listings SHALL still show hidden reviews with their state.
#### Scenario: hidden review leaves the storefront
- **WHEN** a platform admin hides a visible review
- **THEN** it disappears from the product's public review list and no longer contributes to the rating summary
#### Scenario: hide transition validates prior state
- **WHEN** a platform admin hides a review that is already hidden
- **THEN** the guarded transition changes nothing and reports the conflict
### Requirement: Visible-only paginated review listing
A product's review list SHALL be publicly readable and paginated, containing only visible reviews with the reviewer's display name, rating, content, image URLs, creation time, and any merchant reply. Pagination totals SHALL count only visible reviews, and a customer's pending-review listing SHALL show only their own completed order lines without a review.
#### Scenario: totals count only visible reviews
- **WHEN** a product has visible and hidden reviews and the public list is requested
- **THEN** only visible reviews are returned and `total` excludes the hidden ones
#### Scenario: pending-review listing shrinks after submission
- **WHEN** a customer reviews one of their pending order lines
- **THEN** that line disappears from the pending-review listing
### Requirement: SQL rating summary aggregation
The product rating summary SHALL be computed with SQL aggregation over visible reviews only and SHALL report the review count, average rating, and per-star (1-5) distribution. A product without visible reviews SHALL report a zero count, zero average, and an empty distribution.
#### Scenario: summary reflects only visible reviews
- **WHEN** a product's summary is requested after one of its reviews is hidden
- **THEN** the count, average, and star distribution exclude the hidden review
#### Scenario: product without reviews
- **WHEN** the summary is requested for a product with no visible reviews
- **THEN** it reports a zero count and zero average
@@ -0,0 +1,30 @@
## 1. Persistence and shared contract
- [ ] 1.1 Add migration `0017_product_reviews.sql` (0016 is taken by membership/messaging) creating `product_reviews` with an `order_item_id` unique index, cascading order-item/order/product/shop/customer foreign keys, a `rating` 1-5 check, bilingual `content` and `reply` JSONB `{en, zh}` columns, optional `image_urls`, a visibility `status` column, reply audit columns, and product/status and shop listing indexes.
- [ ] 1.2 Add shared `Review`, `ReviewInput`, `ReviewSummary`, `ReviewableOrderItem`, and review query types plus `listProductReviews`, `getProductReviewSummary`, `listReviewableItems`, `createReview`, `listShopReviews`, `replyReview`, `listModerationReviews`, `hideReview`, and `deleteReview` methods to `@vmall/shared`.
- [ ] 1.3 Implement `apps/api/src/modules/review/` repository, service (returning `ApiResult<Dto>`), DTO, handlers, and module registration with customer routes, merchant routes declaring roles and scoping shop resources through `own_shop`, and admin routes declaring the platform role.
- [ ] 1.4 Implement completed-order-line precondition checks, duplicate-review rejection backed by the unique index, a single guarded merchant reply (`UPDATE ... WHERE reply IS NULL`), guarded visibility transitions (`UPDATE ... WHERE status = ...`), visible-only public filtering, and SQL-aggregated rating summaries (average, count, per-star counts) over visible reviews.
## 2. Backend behavioral proof
- [ ] 2.1 Add API integration coverage in `apps/api/tests/` reusing `tests/common/mod.rs` fixtures for creation preconditions and unique-index enforcement, customer ownership and role checks, `own_shop` scoping on merchant routes, one-reply enforcement, guarded hide/delete transitions, hidden-review filtering from public lists and summaries, and rating aggregation with hidden rows excluded.
- [ ] 2.2 Run the focused review integration tests twice to prove pagination totals stay correct against the shared non-truncated test database.
## 3. Mall review surfaces and adapter
- [ ] 3.1 Implement the nine review client methods in `apps/mall/mock/api.ts` with per-session mutable fixture state and the same one-review-per-line, one-reply, and visible-only behavior as the live backend.
- [ ] 3.2 Add the `reviews` domain and exact shared-client method picks to `LIVE_PICKS` in `apps/mall/plugins/api.ts` and enable it in `DEFAULT_LIVE_DOMAINS`.
- [ ] 3.3 Add or adjust bilingual review loading, submission, reply, and failure strings through the existing Mall locale source without per-page hard-coded copy.
- [ ] 3.4 Replace the product-detail display-only comment placeholder and the "no reviews tab" comment in `apps/mall/pages/goods/[id].vue` with the real review tab: rating summary (average, count, star distribution), paginated visible reviews with images and merchant replies, and pagination totals from the API.
- [ ] 3.5 Add the buyer-center "pending review" entry and submission form: list completed order lines awaiting review with counts, submit rating, text, and optional image URLs once per line, and refresh the pending list after submission.
## 4. Merchant and platform consoles
- [ ] 4.1 Add a shop-admin review list/reply page scoped to the merchant's own shop with pagination and one-reply submission through the shared contract.
- [ ] 4.2 Add the admin review moderation list with hide (soft delete) and delete actions plus console navigation.
## 5. Verification and tracker cleanup
- [ ] 5.1 Seed a deterministic completed order with unreviewed lines, run the API plus Mall, and browser-smoke review submission from the buyer center, product-detail summary and paginated list refresh, merchant reply in shop-admin, admin hide removing the review from the storefront and its summary, and the fixed-adapter review flow.
- [ ] 5.2 Run the review integration tests in `apps/api/tests/` (reusing `tests/common/mod.rs` fixtures) and build all three frontends because the shared contract changes: `pnpm --filter @vmall/mall build`, `pnpm --filter @vmall/shop-admin build`, and `pnpm --filter @vmall/admin build`.
- [ ] 5.3 Mark Reviews implemented in `docs/TBD-marketing.md` and update the README mock boundary, check every OpenSpec task, and run `openspec change validate add-product-reviews --strict` plus `openspec validate --all --strict`.