Initial commit: nick docs
This commit is contained in:
95
02 - Data Models/Review.md
Normal file
95
02 - Data Models/Review.md
Normal file
@@ -0,0 +1,95 @@
|
||||
---
|
||||
title: Review
|
||||
tags: [data-model, mongoose]
|
||||
aliases: [Rating, IReview]
|
||||
---
|
||||
|
||||
# Review
|
||||
|
||||
Polymorphic 1-5 star review. The `subjectType` discriminator (`seller` or `template`) plus `subjectId` identifies what is being reviewed. `sellerId` is always present so per-seller aggregations work regardless of subject. A compound unique index on `(subjectType, subjectId, reviewerId)` prevents a reviewer from posting two reviews for the same subject.
|
||||
|
||||
> [!note] Source
|
||||
> `backend/src/models/Review.ts:19` — schema definition
|
||||
> `backend/src/models/Review.ts:38` — model export
|
||||
|
||||
## Schema
|
||||
|
||||
| Field | Type | Required | Default | Validation | Index | Description |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| `subjectType` | String | yes | — | enum: `seller` / `template` | yes (compound) | Discriminator. |
|
||||
| `subjectId` | ObjectId | yes | — | — | yes (compound) | Id of the seller [[User]] or [[RequestTemplate]]. |
|
||||
| `sellerId` | ObjectId → [[User]] | yes | — | — | — | Seller associated with the review (always populated). |
|
||||
| `reviewerId` | ObjectId → [[User]] | yes | — | — | yes (compound + unique) | Author. |
|
||||
| `rating` | Number | yes | — | min 1, max 5 | — | Star rating. |
|
||||
| `comment` | String | no | `""` | maxlength 1000 | — | Free-form comment. |
|
||||
| `isVerifiedBuyer` | Boolean | no | `false` | — | — | Whether the reviewer actually bought from this seller. |
|
||||
| `purchaseRequestId` | ObjectId → [[PurchaseRequest]] | no | `null` | — | — | Source request (if any). |
|
||||
| `status` | String | no | `published` | enum: `published` / `pending` / `rejected` | — | Moderation status. |
|
||||
| `createdAt` | Date | auto | — | — | yes (compound, desc) | Mongoose timestamp. |
|
||||
| `updatedAt` | Date | auto | — | — | — | Mongoose timestamp. |
|
||||
|
||||
## Virtuals
|
||||
|
||||
None defined.
|
||||
|
||||
## Indexes
|
||||
|
||||
Defined at `backend/src/models/Review.ts:34-36`:
|
||||
|
||||
- `{ subjectType: 1, subjectId: 1, createdAt: -1 }` — listing for a subject.
|
||||
- `{ reviewerId: 1, subjectType: 1 }` — reviewer history.
|
||||
- `{ subjectType: 1, subjectId: 1, reviewerId: 1 }` — **unique**, one review per reviewer per subject.
|
||||
|
||||
## Pre/Post Hooks
|
||||
|
||||
None declared.
|
||||
|
||||
## Instance Methods
|
||||
|
||||
None defined.
|
||||
|
||||
## Static Methods
|
||||
|
||||
None defined.
|
||||
|
||||
## Relationships
|
||||
|
||||
- **References**: [[User]] (`sellerId`, `reviewerId`, and `subjectId` when `subjectType === 'seller'`), [[RequestTemplate]] (`subjectId` when `subjectType === 'template'`), [[PurchaseRequest]] (`purchaseRequestId`).
|
||||
- **Referenced by**: none.
|
||||
|
||||
## State Transitions
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> published : default
|
||||
[*] --> pending : moderation required
|
||||
pending --> published : approved
|
||||
pending --> rejected : rejected
|
||||
published --> rejected : flagged
|
||||
rejected --> [*]
|
||||
```
|
||||
|
||||
## Common Queries
|
||||
|
||||
```ts
|
||||
// All reviews for a seller
|
||||
Review.find({ subjectType: 'seller', subjectId: sellerUserId, status: 'published' })
|
||||
.sort({ createdAt: -1 });
|
||||
|
||||
// Average rating per seller
|
||||
Review.aggregate([
|
||||
{ $match: { subjectType: 'seller', subjectId: sellerUserId, status: 'published' } },
|
||||
{ $group: { _id: null, avg: { $avg: '$rating' }, count: { $sum: 1 } } }
|
||||
]);
|
||||
|
||||
// Reviews written by a user
|
||||
Review.find({ reviewerId: userId }).sort({ createdAt: -1 });
|
||||
|
||||
// Reviews for a template
|
||||
Review.find({ subjectType: 'template', subjectId: templateId, status: 'published' });
|
||||
```
|
||||
|
||||
> [!warning] Duplicate prevention
|
||||
> Attempting to insert a second review for the same `(subjectType, subjectId, reviewerId)` will fail with a `E11000 duplicate key` error from MongoDB. Application code should treat that as "already reviewed".
|
||||
|
||||
Related: [[User]], [[RequestTemplate]], [[PurchaseRequest]].
|
||||
Reference in New Issue
Block a user