Overview
TrackGeek’s review system allows users to provide detailed, structured feedback on media with category-specific ratings tailored to each media type. Each review includes an overall rating, optional category ratings, written feedback, and recommendation status.
Review Architecture
Common Features
All review models share these characteristics:
Unique Constraint : One review per user per media item
Overall Rating : Required decimal rating (0-10)
Category Ratings : Optional decimal ratings (0-10) specific to media type
Written Content : Summary, notes, pros/cons, recommendations
Timestamps : Automatic createdAt and updatedAt
Rating Scale
All ratings use a 0-10 decimal scale for precision:
@ IsDecimal ()
@ Max ( 10 )
@ Min ( 0 )
readonly overall : number ;
Source : src/modules/anime-review/dtos/create-anime-review.dto.ts:4-7
Decimal ratings allow for granular scores like 7.5, 8.3, etc., providing more nuanced reviews than integer scales.
Anime Reviews
Manga Reviews
TV Show Reviews
Movie Reviews
Game Reviews
Book Reviews
AnimeReview Model Anime reviews focus on animation-specific quality metrics. model AnimeReview {
id String @id @default ( uuid ())
overall Decimal
story Decimal ?
characters Decimal ?
animation Decimal ?
sound Decimal ?
enjoyment Decimal ?
summary String ?
notes String ?
pros String ?
cons String ?
recommended Boolean ?
userId String
animeId String
createdAt DateTime @default ( now ())
updatedAt DateTime @updatedAt
user User @relation ( fields : [ userId ], references : [ id ] )
anime Anime @relation ( fields : [ animeId ], references : [ id ] )
@@unique ( [ userId , animeId ] )
}
Source : prisma/schema.prisma:734-756Rating Categories
Evaluates narrative quality, plot development, pacing, and storytelling. Consider:
Plot coherence and originality
Character arcs and development
Pacing and narrative structure
Theme execution
Evaluates character design, development, and relationships. Consider:
Character depth and growth
Personality distinctiveness
Relationship dynamics
Voice acting performance
Evaluates visual quality, art style, and animation fluidity. Consider:
Art style and consistency
Animation fluidity
Action scene choreography
Visual effects and cinematography
Evaluates audio quality, music, sound effects, and voice acting. Consider:
Opening/ending themes
Background music (OST)
Sound effect quality
Voice acting performance
Subjective measure of personal enjoyment regardless of technical quality. Consider:
Emotional impact
Rewatchability
Personal connection
Entertainment value
Written Content Field Max Length Description summary250 chars Brief review summary pros500 chars Positive aspects cons500 chars Negative aspects notes1000 chars Additional thoughts
DTO Validation (src/modules/anime-review/dtos/create-anime-review.dto.ts:39-53):@ IsOptional ()
@ MaxLength ( 250 )
readonly summary ?: string ;
@ IsOptional ()
@ MaxLength ( 500 )
readonly pros ?: string ;
@ IsOptional ()
@ MaxLength ( 500 )
readonly cons ?: string ;
@ IsOptional ()
@ MaxLength ( 1000 )
readonly notes ?: string ;
MangaReview Model Manga reviews emphasize visual storytelling and worldbuilding. model MangaReview {
id String @id @default ( uuid ())
overall Decimal
art Decimal ?
worldbuilding Decimal ?
summary String ?
notes String ?
story String ?
characters String ?
recommended Boolean ?
userId String
mangaId String
createdAt DateTime @default ( now ())
updatedAt DateTime @updatedAt
user User @relation ( fields : [ userId ], references : [ id ] )
manga Manga @relation ( fields : [ mangaId ], references : [ id ] )
@@unique ( [ userId , mangaId ] )
}
Source : prisma/schema.prisma:758-777Rating Categories
Evaluates visual art quality, panel composition, and character designs. Consider:
Art style and detail
Panel composition and flow
Character design uniqueness
Background art quality
Evaluates setting development, lore, and world consistency. Consider:
Setting depth and originality
Lore and mythology
World consistency
Cultural elements
Written Content Unlike anime, manga reviews use text fields for story and characters instead of decimal ratings, allowing more nuanced narrative feedback.
Field Type Description summaryString Brief review summary storyString Narrative analysis charactersString Character analysis notesString Additional thoughts
TvShowReview Model TV show reviews focus on production quality and performance. model TvShowReview {
id String @id @default ( uuid ())
overall Decimal
direction Decimal ?
production Decimal ?
acting Decimal ?
summary String ?
notes String ?
story String ?
recommended Boolean ?
userId String
tvShowId String
createdAt DateTime @default ( now ())
updatedAt DateTime @updatedAt
user User @relation ( fields : [ userId ], references : [ id ] )
tvShow TvShow @relation ( fields : [ tvShowId ], references : [ id ] )
@@unique ( [ userId , tvShowId ] )
@@map ( "TVShowReview" )
}
Source : prisma/schema.prisma:779-799Rating Categories
Evaluates directorial vision, episode pacing, and visual storytelling. Consider:
Episode pacing and structure
Cinematography and shot composition
Directorial consistency
Visual storytelling techniques
Evaluates production values, set design, costumes, and special effects. Consider:
Set design and locations
Costume design
Visual/special effects
Overall production quality
Evaluates acting performances and character portrayals. Consider:
Lead performances
Supporting cast
Chemistry between actors
Character authenticity
MovieReview Model Movie reviews use the same categories as TV shows (direction, production, acting). model MovieReview {
id String @id @default ( uuid ())
overall Decimal
direction Decimal ?
production Decimal ?
acting Decimal ?
summary String ?
notes String ?
story String ?
recommended Boolean ?
userId String
movieId String
createdAt DateTime @default ( now ())
updatedAt DateTime @updatedAt
user User @relation ( fields : [ userId ], references : [ id ] )
movie Movie @relation ( fields : [ movieId ], references : [ id ] )
@@unique ( [ userId , movieId ] )
}
Source : prisma/schema.prisma:801-820Movie reviews share the same rating categories as TV shows since both are live-action visual media with similar production considerations.
GameReview Model Game reviews include gameplay-specific metrics and optional screenshots. model GameReview {
id String @id @default ( uuid ())
overall Decimal
graphics Decimal ?
sound Decimal ?
story Decimal ?
gameplay Decimal ?
platform String ?
summary String ?
notes String ?
recommended Boolean ?
screenshots String [] @default ( [] )
userId String
gameId String
createdAt DateTime @default ( now ())
updatedAt DateTime @updatedAt
user Game @relation ( fields : [ userId ], references : [ id ] )
game Game @relation ( fields : [ gameId ], references : [ id ] )
@@unique ( [ userId , gameId ] )
}
Source : prisma/schema.prisma:822-843Rating Categories
Evaluates visual quality, art direction, and technical performance. Consider:
Visual fidelity and art style
Animation quality
Performance and frame rate
Character and environment design
Evaluates audio design, music, and voice acting. Consider:
Soundtrack quality
Sound effects
Voice acting performance
Audio mixing and immersion
Evaluates narrative quality, writing, and character development. Consider:
Plot and narrative structure
Character development
Dialogue quality
Worldbuilding and lore
Evaluates mechanics, controls, and overall gameplay experience. Consider:
Core mechanics and controls
Game balance and difficulty
Level design
Innovation and fun factor
Unique Features
Platform Tracking Optional platform field to specify which platform was played (PS5, PC, Xbox, Switch, etc.)
Screenshots Array of screenshot URLs to showcase gameplay moments
BookReview Model Book reviews focus on literary quality and thematic elements. model BookReview {
id String @id @default ( uuid ())
overall Decimal
characters Decimal ?
language Decimal ?
theme Decimal ?
summary String ?
notes String ?
recommended Boolean ?
userId String
bookId String
createdAt DateTime @default ( now ())
updatedAt DateTime @updatedAt
user User @relation ( fields : [ userId ], references : [ id ] )
book Book @relation ( fields : [ bookId ], references : [ id ] )
@@unique ( [ userId , bookId ] )
}
Source : prisma/schema.prisma:845-863Rating Categories
Evaluates character depth, development, and relatability. Consider:
Character complexity
Character growth arcs
Relationship dynamics
Character authenticity
Evaluates writing quality, prose style, and literary technique. Consider:
Prose quality and style
Vocabulary and diction
Writing technique
Readability and flow
Evaluates thematic depth, message clarity, and philosophical content. Consider:
Thematic depth and complexity
Message and meaning
Philosophical elements
Social commentary
Recommendation System
All review types include an optional recommended boolean field:
This allows users to give a clear yes/no recommendation independent of numerical ratings.
Positive but not recommended : High technical quality but niche appeal
Negative but recommended : Flawed but unique or important
No recommendation : User is neutral or undecided
Review Creation Flow
Review creation follows a consistent pattern across all media types:
Example from AnimeReviewService (src/modules/anime-review/anime-review.service.ts:20-60):
async createAnimeReview ( createAnimeReviewDto : CreateAnimeReviewDto ) {
const animeReview = await this . databaseService . animeReview . create ({
data: {
overall: createAnimeReviewDto . overall ,
story: createAnimeReviewDto . story ,
characters: createAnimeReviewDto . characters ,
animation: createAnimeReviewDto . animation ,
sound: createAnimeReviewDto . sound ,
enjoyment: createAnimeReviewDto . enjoyment ,
summary: createAnimeReviewDto . summary ,
pros: createAnimeReviewDto . pros ,
cons: createAnimeReviewDto . cons ,
notes: createAnimeReviewDto . notes ,
recommended: createAnimeReviewDto . recommended ,
animeId: createAnimeReviewDto . animeId ,
userId: createAnimeReviewDto . userId ,
},
include: {
anime: true ,
user: {
select: {
id: true ,
name: true ,
username: true ,
profile: {
select: {
id: true ,
avatarUrl: true ,
},
},
},
},
},
});
await this . queueService . toFeedEventQueue ({
type: FeedEventType . NewReview ,
userId: createAnimeReviewDto . userId ,
metadata: { animeReview },
});
}
Flow Steps
Validation : DTO validates all rating ranges (0-10) and string lengths
Creation : Insert review with all provided fields
Relations : Include media and user data in response
Feed Event : Queue a NewReview event for follower feeds
Feed Event Integration
Reviews trigger feed events to notify followers:
Feed Event Type (prisma/schema.prisma:235):
The event metadata contains the full review object including:
All ratings (overall + categories)
Written content (summary, notes, pros/cons)
Recommendation status
Related media details
User information
Review Queries
The review system supports various query patterns:
Example (src/modules/anime-review/anime-review.service.ts:90-118):
async getAnimeReviews ( getAnimeReviewsDto : GetAnimeReviewsDto ) {
const animeReviews = await this . databaseService . offsetPagination < AnimeReviewFindManyArgs >({
model: "animeReview" ,
itemsPerPage: getAnimeReviewsDto . itemsPerPage ,
page: getAnimeReviewsDto . page ,
where: {
animeId: getAnimeReviewsDto . animeId ,
userId: getAnimeReviewsDto . userId ,
},
include: {
anime: true ,
user: {
select: {
id: true ,
name: true ,
username: true ,
profile: {
select: {
id: true ,
avatarUrl: true ,
},
},
},
},
},
});
return animeReviews ;
}
Get Single Review
Example (src/modules/anime-review/anime-review.service.ts:62-88):
async getAnimeReviewById ( animeReviewId : string ) {
const animeReview = await this . databaseService . animeReview . findUnique ({
where: { id: animeReviewId },
include: {
anime: true ,
user: {
select: {
id: true ,
name: true ,
username: true ,
profile: {
select: {
id: true ,
avatarUrl: true ,
},
},
},
},
},
});
if ( ! animeReview ) {
throw new AppException ( ERROR_CODES . REVIEW_NOT_FOUND );
}
return animeReview ;
}
Review Updates
Users can update their reviews with authorization checks:
Example (src/modules/anime-review/anime-review.service.ts:120-149):
async updateAnimeReview ( updateAnimeReviewDto : UpdateAnimeReviewDto ) {
const animeReview = await this . databaseService . animeReview . findUnique ({
where: {
id: updateAnimeReviewDto . animeReviewId ,
},
});
if ( ! animeReview || animeReview . userId !== updateAnimeReviewDto . userId ) {
throw new AppException ( ERROR_CODES . REVIEW_NOT_FOUND );
}
await this . databaseService . animeReview . update ({
where: {
id: animeReview . id ,
},
data: {
overall: updateAnimeReviewDto . overall ,
story: updateAnimeReviewDto . story ,
characters: updateAnimeReviewDto . characters ,
animation: updateAnimeReviewDto . animation ,
sound: updateAnimeReviewDto . sound ,
enjoyment: updateAnimeReviewDto . enjoyment ,
summary: updateAnimeReviewDto . summary ,
pros: updateAnimeReviewDto . pros ,
cons: updateAnimeReviewDto . cons ,
notes: updateAnimeReviewDto . notes ,
recommended: updateAnimeReviewDto . recommended ,
},
});
}
Updates verify that the review belongs to the requesting user before allowing modifications.
Review Deletion
Deletion follows the same authorization pattern:
Example (src/modules/anime-review/anime-review.service.ts:151-166):
async deleteAnimeReview ( deleteAnimeReviewDto : DeleteAnimeReviewDto ) {
const animeReview = await this . databaseService . animeReview . findUnique ({
where: {
id: deleteAnimeReviewDto . animeReviewId ,
},
});
if ( ! animeReview || animeReview . userId !== deleteAnimeReviewDto . userId ) {
throw new AppException ( ERROR_CODES . REVIEW_NOT_FOUND );
}
await this . databaseService . animeReview . delete ({
where: { id: animeReview . id },
});
}
Aggregate Statistics
Reviews enable powerful aggregate statistics:
Average Ratings Calculate average overall and category ratings per media
Review Count Total number of reviews per media
Recommendation Rate Percentage of users who recommend the media
Rating Distribution Histogram of rating ranges
Top Rated Media sorted by highest average ratings
Most Reviewed Media with most review activity
Best Practices
Require Overall Always require the overall rating; make category ratings optional
Validate Ranges Enforce 0-10 range validation at DTO level
Character Limits Set reasonable limits on text fields to encourage concise reviews
User Authorization Always verify review ownership before updates/deletes
Include Relations Return media and user data with reviews for context
Feed Integration Queue feed events after successful review creation