Skip to main content

Interactions Module

The community engagement engine – product reviews, threaded comments, and helpfulness voting.

Reviews Threaded Voting


📖 Table of Contents


Base Route : /api/v1/interactions

Public endpoints (GET /product/:productId) are open to all. Write endpoints (POST /, PATCH /.../vote) require a valid access token (authenticated user).


Endpoints Overview

MethodEndpointAccessDescription
GET/product/:productIdPublicFetch paginated top‑level reviews for a product (includes nested comments)
POST/Private (Bearer)Create a new review or a threaded comment
PATCH/:interactionId/votePrivate (Bearer)Upvote or downvote an existing interaction

Rate limits: standardLimiter applies (100 requests per 15 minutes per IP). Public endpoint also uses standardLimiter.


Endpoint Details

GET /product/:productId

Fetch all reviews (top‑level) for a specific product, with their nested comments. Paginated to prevent large payloads.

Headers: None required.

URL Parameter: productId – valid MongoDB ObjectId of the product.

Query parameters:

ParamTypeDefaultMaxDescription
pageinteger1Page number (1‑based)
limitinteger1050Items per page (capped at 50)

Example request:

GET /api/v1/interactions/product/64a7b...?page=1&limit=10

Response (200 OK):

{
"success": true,
"statusCode": 200,
"message": "Product interactions retrieved successfully",
"data": {
"interactions": [
{
"_id": "...",
"type": "REVIEW",
"productId": "64a7b...",
"userId": { "_id": "...", "firstname": "John", "avatar": "..." },
"rating": 5,
"content": "Absolutely love this product!",
"voteCount": 12,
"createdAt": "2026-05-20T10:00:00.000Z",
"comments": [
{
"_id": "...",
"type": "COMMENT",
"parentId": "...",
"userId": { "_id": "...", "firstname": "Admin", "avatar": "..." },
"content": "Thank you for your review!",
"createdAt": "2026-05-21T12:00:00.000Z"
}
]
}
],
"meta": {
"total": 25,
"limit": 10,
"page": 1
}
},
"timestamp": "2026-05-22T10:30:00.000Z"
}

Only top‑level interactions (type: "REVIEW") are returned. Comments are nested under their parent review.

POST /

Create a new interaction – either a review (top‑level) or a comment (reply to an existing review).

Headers: Authorization: Bearer <access_token>

Request body for a REVIEW:

{
"productId": "64a7b...",
"type": "REVIEW",
"rating": 5,
"content": "Amazing quality, fast shipping!"
}

Response (201 Created):

{
"success": true,
"statusCode": 201,
"message": "Interaction created successfully",
"data": {
"_id": "...",
"type": "REVIEW",
"productId": "64a7b...",
"userId": "...",
"rating": 5,
"content": "Amazing quality, fast shipping!",
"voteCount": 0,
"createdAt": "2026-05-22T10:35:00.000Z"
},
"timestamp": "2026-05-22T10:35:00.000Z"
}

Business rules:

  • A user can submit only one review per product (duplicate reviews return 409 Conflict).
  • Comments can be nested arbitrarily (threaded).
  • rating is only allowed for type: "REVIEW" – if provided in a COMMENT, it is rejected.

PATCH /:interactionId/vote

Upvote or downvote an interaction (review or comment). A user can vote only once per interaction; subsequent votes toggle (remove vote if same action, change if different).

Headers:
Authorization: Bearer <access_token>

URL Parameter:

  • interactionId – ID of the review or comment.

Request body:

{
"action": "LIKE" // or "DISLIKE"
}

Response (200 OK):

{
"success": true,
"statusCode": 200,
"message": "Vote recorded successfully",
"data": {
"interactionId": "...",
"voteCount": 13,
"userVote": "LIKE" // null if removed
},
"timestamp": "2026-05-22T10:40:00.000Z"
}

Vote logic:

  • If user has not voted → adds vote, increments voteCount.
  • If user has voted with same action → removes vote, decrements voteCount.
  • If user has voted with opposite action → changes vote, voteCount unchanged (e.g., +1 then -1).

Validation Rules (Zod)

EndpointFieldRules
POST / (REVIEW)productIdvalid ObjectId, required
typemust be "REVIEW", required
ratinginteger 1‑5, required
contentstring, 3‑2000 chars, required
POST / (COMMENT)productIdvalid ObjectId, required
typemust be "COMMENT", required
parentIdvalid ObjectId (must exist as a review), required
contentstring, 3‑2000 chars, required
PATCH /:interactionId/voteactionenum ["LIKE", "DISLIKE"], required

All schemas use .strict() – extra fields are rejected. The rating field is forbidden in COMMENT requests (Zod refinement).


Error Responses

StatusCodeExample messageWhen
400BAD_REQUEST"Rating is forbidden on threaded COMMENTS"Comment includes rating field
400BAD_REQUEST"Parent interaction must be a REVIEW"Comment references another comment
401UNAUTHORIZED"Authentication required"Missing/invalid token for write endpoints
404NOT_FOUND"Product not found"Invalid productId
404NOT_FOUND"Parent interaction not found"Invalid parentId for comment
409CONFLICT"You have already submitted a review for this product"Duplicate review
429TOO_MANY_REQUESTS"Too many requests, please try again later."Rate limit exceeded

Runbook

For manual testing with Thunder Client / Postman, see ../../testing/interaction-runbook.md. The runbook covers:

  • Creating a product review with rating
  • Replying to a review with a comment
  • Upvoting and downvoting
  • Fetching paginated reviews for a product
  • Edge cases: duplicate review, rating on comment, invalid parent


Authentic feedback, community driven – the Reshma‑Core interaction engine.