---
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
