--- title: Rating Flow tags: [flow, rating, review, moderation] related_models: ["[[Review]]", "[[ShopSettings]]", "[[PurchaseRequest]]"] related_apis: ["POST /api/marketplace/reviews", "GET /api/marketplace/reviews/:subjectType/:subjectId"] --- # Rating Flow > **Last updated:** 2026-05-29 — aligned with code (see [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)) > [!caution] Not deeply audited > This flow was not deeply covered by the 2026-05-29 audit; endpoints should be verified against `reviewRoutes`/`marketplaceController` before relying on them for UAT. After an order is `completed`, the buyer rates the seller and (optionally) leaves a review; the seller can rate the buyer in the reciprocal flow. Reviews are scoped by `subjectType` (`seller` | `template`) and constrained by the seller's `ShopSettings`. ## Actors - **Buyer** (typical reviewer). - **Seller** (subject; can also be a reviewer in the reciprocal direction). - **System** — enforces uniqueness and moderation rules. - **Backend** — `backend/src/services/marketplace/reviewRoutes.ts`. - **MongoDB** — `reviews` collection (`backend/src/models/Review.ts`). ## Preconditions - The associated `PurchaseRequest` is `completed` (or `finalized`). - The reviewer is the buyer of that request (for `isVerifiedBuyer` to be `true`). - The subject's `ShopSettings.allowSellerReviews` / `allowTemplateReviews` is not `false` (`reviewRoutes.ts:15-31`). ## Step-by-step narrative 1. From the request detail or seller profile, the buyer clicks "Leave review". The form captures `rating` (1–5) and `comment` (≤ 1000 chars). 2. Frontend POSTs `POST /api/marketplace/reviews` with `{ subjectType: 'seller' | 'template', subjectId, rating, comment, purchaseRequestId? }`. 3. Backend route handler: - Validates payload. - Calls `isReviewsAllowed(subjectType, subjectId)` — checks the seller's `ShopSettings` (for sellers, look up the seller directly; for templates, look up the template's owning seller). - Sets `isVerifiedBuyer = true` if the user owns a `completed` purchase request from that seller. - Defaults `status: 'published'` (no moderation queue today). 4. Inserts a `Review` document. Unique index `{ subjectType, subjectId, reviewerId }` prevents a user from reviewing the same subject twice (`Review.ts:34`). 5. Aggregated stats are recomputed on read via `computeStats` (`reviewRoutes.ts:33-62`) — count, average, per-star histogram. No denormalised counter on `User` today; everything is computed at read-time. ## Visibility - Public — anyone hitting `GET /api/marketplace/reviews/seller/:sellerId` sees `status: 'published'` reviews paginated by 10. - If `ShopSettings.allowSellerReviews === false` (or `allowTemplateReviews === false`), reads return `403 Reviews are disabled by seller`. - The seller can flag a review for moderation (planned — current statuses include `pending` and `rejected`, but no UI to flip them today; admin can update via direct DB). ## Sequence diagram ```mermaid sequenceDiagram autonumber actor B as Buyer participant FE as Frontend participant BE as Backend participant DB as MongoDB B->>FE: Open seller profile / request detail B->>FE: Click "Leave review", choose stars + comment FE->>BE: POST /api/marketplace/reviews BE->>DB: ShopSettings.findOne({sellerId}) → allowSellerReviews? alt allowed BE->>DB: PurchaseRequest.exists({buyer, seller, status:"completed"})? BE->>DB: Review.create({status:"published", isVerifiedBuyer}) BE-->>FE: 201 { review } else disabled BE-->>FE: 403 Reviews disabled end Note over FE: Public visitor: FE->>BE: GET /api/marketplace/reviews/seller/{id} BE->>DB: Review.find / computeStats aggregate BE-->>FE: { items, pagination, stats:{count, avg, histogram} } ``` ## API calls | Method | Endpoint | Purpose | |---|---|---| | `POST` | `/api/marketplace/reviews` | Submit review | | `GET` | `/api/marketplace/reviews/:subjectType/:subjectId` | List reviews + stats | | `PATCH` | `/api/marketplace/reviews/:id` | Edit own review (within edit window) | | `DELETE` | `/api/marketplace/reviews/:id` | Delete own review | ## Database writes - **`reviews`** — insert on submission; one document per `(subjectType, subjectId, reviewerId)`. - **`shopsettings`** — read-only here; the seller controls `allowSellerReviews` / `allowTemplateReviews` in their shop settings. ## Socket events emitted - None today. A `new-review` event broadcast to `user-{sellerId}` would be a useful enhancement so sellers see reviews appear live. ## Side effects - Recompute aggregate on every list call — fine for small volumes; consider caching `stats` per subject when the review count grows. - Order rating field also stamps `metadata.rating` on the purchase request when the marketplace endpoint accepts ratings inline (see `routes.ts` references in `backend/src/services/marketplace/routes.ts`). ## Error / edge cases - **Duplicate review** → MongoDB `E11000` from the unique index; surface as `409 Already reviewed`. - **Subject disabled reviews** → `403`. - **Reviewer not a verified buyer** → review is still allowed but `isVerifiedBuyer = false`. Display this in the UI. - **Rating out of 1–5** → Mongoose schema validator rejects. - **Comment > 1000 chars** → schema-level rejection. - **Seller toggles `allowSellerReviews=false` after reviews exist** → existing reviews remain stored but become unreadable via the public GET (`reviewRoutes.ts:81-83`). - **Spam / abuse** → no automatic moderation; admin can flip `status` to `rejected` to hide. > [!tip] Verified-buyer badge > The `isVerifiedBuyer` flag is the most credible signal for prospective buyers. Always render a "Verified buyer" pill next to reviews where this is `true`. ## Linked flows - [[Purchase Request Flow]] — precursor that makes the buyer "verified". - [[Seller Offer Flow]] — display average rating on offer cards. - [[Dispute Flow]] — a resolved dispute could trigger a review prompt; today they are independent. ## Source files - Backend: `backend/src/services/marketplace/reviewRoutes.ts` - Backend: `backend/src/models/Review.ts` - Backend: `backend/src/services/marketplace/shopSettingsController.ts` (allow flags) - Backend: `backend/src/services/marketplace/routes.ts` (inline rating on order completion) - Frontend: review components under `frontend/src/sections/account/` and seller profile views