SRS — Reviews & Ratings
Module owner: Domain 8 — Experience. Reviews are Yam3at's trust engine: only customers with a Completed booking can review, which makes every star on a vendor profile a verified transaction — the platform's core differentiation over Instagram vendor-shopping.
Related: Booking · Admin & CMS · Vendor profiles (Listings module)
Purpose
Convert completed bookings into credible, fraud-resistant social proof that powers vendor ranking, customer decisions and the compare view — while giving vendors a fair right of reply and admins a workable moderation pipeline.
Actors
| Actor |
Role |
| Customer |
Writes/edits one review per completed booking; reports abusive replies |
| Vendor |
Reads reviews, posts one public reply per review, reports abusive reviews |
| Admin (support/ops) |
Moderates the queue, resolves reports, hides/restores reviews |
| System |
Opens review windows, recomputes rating aggregates, auto-screens content |
User stories
- As a customer, I want to rate my photographer on quality, punctuality and value with photos, so that the next bride knows what she's actually getting.
- As a customer, I want to fix a typo in my review within a few days, so that my honest words stay accurate.
- As a vendor, I want to reply publicly to a review, so that my side of a bad experience is visible.
- As a vendor, I want reviews only from real completed bookings, so that a competitor can't torch my rating with fakes.
- As an admin, I want a moderation queue with report reasons and booking context, so that I resolve disputes about reviews quickly and consistently.
Functional requirements
Creation & editing — MVP
| ID |
Requirement |
Phase |
| SRS-REV-001 |
Review window opens when a booking reaches completed (SRS-BKG-017) and stays open 90 days. Exactly one review per booking. Invitation via review.invite notification + persistent CTA on the booking and event dashboard. |
MVP |
| SRS-REV-002 |
Review composition: overall_rating 1–5 (required, integer stars), optional criteria ratings 1–5 each — quality, punctuality, value for money — optional title, body, and up to 5 photos. |
MVP |
| SRS-REV-003 |
Reviews publish immediately (post-moderation model) unless auto-screening flags them (blocked words, contact info, links) — flagged reviews go to the moderation queue in pending_moderation and show to the author only as "under review". |
MVP |
| SRS-REV-004 |
Edit window: author may edit or delete their review within 7 days of publishing (edits re-run auto-screening; "edited" label shown). After 7 days the review is locked; deletion after the window requires a support request. |
MVP |
| SRS-REV-005 |
Vendor public reply: one reply per review (text only, ≤ 1,000 chars), editable by the vendor within 7 days of posting the reply, displayed beneath the review. Replies pass the same auto-screening. |
MVP |
Moderation — MVP
| ID |
Requirement |
Phase |
| SRS-REV-010 |
Report-abuse: vendors can report reviews, customers can report replies (reason enum: fake, offensive, personal info, off-topic, blackmail/extortion + note). Reports create moderation cases; a review with an open report stays visible unless the reason is personal info or offensive auto-classified (then temporarily hidden pending decision). |
MVP |
| SRS-REV-011 |
Moderation decisions: approve (visible, report closed), hide (removed from public, author notified with reason, counts removed from aggregates), edit-redact (admin redacts personal info only — logged, original preserved), escalate (to dispute handling). All decisions audit-logged with actor and reason. |
MVP |
| SRS-REV-012 |
A hidden review can be appealed once by its author within 14 days; appeal goes to a different moderator than the original decision-maker where staffing allows. |
MVP |
Aggregation — MVP
| ID |
Requirement |
Phase |
| SRS-REV-020 |
Vendor profile aggregates, recomputed transactionally on every review publish/hide/delete: rating_avg = mean of visible reviews' overall_rating, stored decimal(3,2), displayed to 1 dp; rating_count; star distribution (count per 1–5); per-criteria averages (over reviews that rated that criterion). |
MVP |
| SRS-REV-021 |
Display rules: vendors with < 3 reviews show "New — {n} review(s)" instead of an average (prevents a single 1-star from defining a new vendor). Search/compare ranking uses a Bayesian smoothed score: score = (v·R + m·C) / (v + m) where v = review count, R = vendor mean, C = platform-wide mean, m = 5 (damping constant, admin-tunable) — documented so ranking is explainable. |
MVP |
| SRS-REV-022 |
Review listing on vendor profile: sort by newest (default), highest, lowest; filter by star level and by criteria; shows reviewer first name + initial, event type, and month/year of the event (never full names or dates that identify the event precisely). |
MVP |
Anti-fraud — MVP
| ID |
Requirement |
Phase |
| SRS-REV-030 |
Hard rules: one review per booking (DB unique constraint); reviewer must be the booking's customer; no self-review — a vendor account whose owner identity (phone/email/civil-linked user id) matches the customer account is blocked at write time and flagged; reviews impossible on cancelled/refund_requested bookings. |
MVP |
| SRS-REV-031 |
Signals feeding a fraud score for moderator attention (not auto-removal): burst of reviews for one vendor from accounts created < 7 days ago; identical/near-duplicate bodies across accounts (shingling similarity > 0.85); reviewer and vendor sharing device fingerprint or IP ranges repeatedly; ratio of 5-star reviews from bookings with the minimum deposit that were never messaged. Score ≥ threshold → queue with "suspected fraud" tag. |
MVP |
| SRS-REV-032 |
Incentivized-review policy: vendors offering discounts for positive reviews (detected via messaging flags or reports) receive a strike; reviews obtained that way are hidden. Three strikes → account review by operations. |
MVP |
Scale / Vision
| ID |
Requirement |
Phase |
| SRS-REV-040 |
Review helpfulness votes ("Was this helpful?") influencing sort. |
Scale |
| SRS-REV-041 |
AI review summarization on vendor profiles ("What customers consistently praise/criticize"), AR/EN. |
Scale |
| SRS-REV-042 |
Video reviews; verified event-photo watermarking. |
Vision |
Business rules
- Verified-only: no review path exists outside a completed booking — no imported reviews, no vendor-solicited external testimonials shown as reviews.
- Ratings are immutable history: hiding removes from aggregates and public view but never physically deletes (moderation/audit needs); author deletion within the window is a soft delete.
- Vendor replies never affect ratings and cannot be replied to further (no threads).
- Aggregates count only
published (visible) reviews; pending_moderation and hidden are excluded.
- A refund after completion does not auto-remove a review; an admin may hide it only through the standard moderation reasons.
- Reviewer anonymity is partial by design (first name + initial); full anonymity is not offered because accountability deters abuse.
- Photos must originate from the reviewer's upload (no URL imports); EXIF stripped; faces are the reviewer's responsibility per ToS.
Validation rules
| Field |
Rule |
overall_rating |
required, integer 1–5 |
| Criteria ratings |
optional, each integer 1–5, only defined criteria keys (quality, punctuality, value) |
title |
optional, 3–80 chars |
body |
optional but required if any criteria rating < 3 (context for low scores), 10–2,000 chars, no URLs, blocked-words screened |
| Photos |
≤ 5; jpg/png/webp; ≤ 10 MB each; min 400×400 px; virus-scanned, EXIF-stripped |
| Vendor reply |
10–1,000 chars, no URLs, no contact info |
| Report |
reason enum required, note ≤ 1,000 chars |
| Window checks |
create: booking completed and ≤ 90 days; edit: ≤ 7 days since publish; reply edit: ≤ 7 days since reply |
Permissions matrix
| Action |
Customer (booking owner) |
Other customer |
Vendor (reviewed) |
Other vendor |
Admin support |
Admin ops |
Admin super |
| Create review |
✔ (window) |
✘ |
✘ |
✘ |
✘ |
✘ |
✘ |
| Edit/delete own review (≤7d) |
✔ |
✘ |
✘ |
✘ |
✘ |
✘ |
✘ |
| Read published reviews |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
| Post/edit public reply |
✘ |
✘ |
✔ |
✘ |
✘ |
✘ |
✘ |
| Report review/reply |
✔ (replies) |
✘ |
✔ (reviews) |
✘ |
— |
— |
— |
| Moderate (approve/hide/redact) |
✘ |
✘ |
✘ |
✘ |
✔ (logged) |
✔ (logged) |
✔ (logged) |
| Tune damping constant / criteria set |
✘ |
✘ |
✘ |
✘ |
✘ |
✘ |
✔ |
State machine
stateDiagram-v2
[*] --> Draft : customer starts (autosaved)
Draft --> Published : passes auto-screening
Draft --> PendingModeration : auto-screening flags
PendingModeration --> Published : moderator approves
PendingModeration --> Hidden : moderator hides
Published --> Published : author edit ≤7d (re-screened)
Published --> PendingModeration : edit flagged / report auto-hide class
Published --> Hidden : moderation decision
Published --> Deleted : author deletes ≤7d (soft)
Hidden --> Published : appeal upheld / restore
Deleted --> [*]
Hidden --> [*]
Edge cases
- Booking auto-completed, customer later disputes (SRS-BKG edge case): review stays writable; if a refund is granted the review persists with an internal "refunded booking" tag visible to moderators only.
- Vendor replies, then customer edits the review: reply remains with "response to an earlier version" auto-label.
- Customer account deleted after reviewing: review persists anonymized ("Verified customer") — aggregates unchanged.
- Vendor suspended: reviews remain readable on the (unlisted) profile; new replies blocked.
- Rating without body on a low score: blocked by validation (body required < 3 stars) — prevents context-free rating bombs.
- Two moderation decisions racing: case-level lock; second decision sees resolved case.
- 90-day window expires during a
pending_moderation hold: publication proceeds normally on approval; window applies to creation, not moderation latency.
- Same customer books the same vendor twice: two bookings → two reviews allowed (both verified transactions).
Empty / loading / error states
| Surface |
Empty |
Loading |
Error |
| Vendor profile reviews tab |
"No reviews yet — completed bookings unlock reviews" (+ "New vendor" badge logic per SRS-REV-021) |
Skeleton review cards + aggregate shimmer |
Aggregate from cache; list retry |
| Review composer |
— |
Photo upload progress per file |
Draft autosaved locally; submit failure keeps draft; per-photo retry |
| Moderation queue (admin) |
"Queue clear" |
Table skeleton |
Retry; case detail loads independently of list |
| My reviews (customer) |
"Reviews you write appear here" |
Skeleton rows |
Retry banner |
Acceptance criteria
Data entities touched
reviews, review_criteria_ratings, review_photos, review_replies, review_reports, review_moderation_cases, review_appeals, vendor_rating_aggregates (avg, count, distribution, criteria avgs, bayesian score), fraud_signals; reads on bookings, events (event type for display), users, vendors; writes trigger Meilisearch re-index of the vendor document.
POST /api/v1/bookings/{bookingId}/review
GET /api/v1/reviews/{id}
PATCH /api/v1/reviews/{id} # ≤ 7 days, author only
DELETE /api/v1/reviews/{id} # ≤ 7 days, author only
GET /api/v1/vendors/{vendorId}/reviews?sort=&stars=&page=
GET /api/v1/vendors/{vendorId}/rating-summary
POST /api/v1/reviews/{id}/reply # vendor
PATCH /api/v1/review-replies/{id} # ≤ 7 days
POST /api/v1/reviews/{id}/report
POST /api/v1/review-replies/{id}/report
GET /api/v1/me/reviews # customer's written reviews
# admin
GET /api/v1/admin/moderation/reviews?status=pending|reported
POST /api/v1/admin/moderation/reviews/{caseId}/decide # approve|hide|redact|escalate
POST /api/v1/admin/reviews/{id}/restore