Skip to main content

Overview

The progress tracking system allows users to track their consumption status across all six media types. Each media type has specialized tracking models that capture viewing/reading/playing progress with appropriate granularity.

Progress Models

TrackGeek uses two types of progress tracking:
  1. Watch/Read Models: Legacy models for anime, manga, TV shows, movies, and books with episode/chapter tracking
  2. Progress Models: Unified progress tracking for all six media types with standardized status tracking

Progress Status Enum

All progress models use the ProgressStatus enum for consistency:
enum ProgressStatus {
  Watching
  Playing
  Reading
  Completed
  Paused
  Dropped
  Planning
}
Source: prisma/schema.prisma:633-641
The status names are context-aware. “Watching” applies to anime/TV/movies, “Playing” to games, and “Reading” to books/manga.

Watch Status Enum

Legacy watch models use the WatchStatus enum:
enum WatchStatus {
  Watching
  Completed
  Paused
  Dropped
  Planning
}
Source: prisma/schema.prisma:523-529

Read Status Enum

Legacy read models use the ReadStatus enum:
enum ReadStatus {
  Reading
  Completed
  Paused
  Dropped
  Planning
}
Source: prisma/schema.prisma:587-593

Database Schema

AnimeProgress Model

Tracks anime watching progress with status tracking.
model AnimeProgress {
  id        String         @id @default(uuid())
  status    ProgressStatus
  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])
  @@index([userId])
}
Source: prisma/schema.prisma:643-656

AnimeWatch Model (Legacy)

Legacy model with episode tracking:
model AnimeWatch {
  id          String      @id @default(uuid())
  season      Int
  episode     Int
  status      WatchStatus
  userId      String
  animeId     String
  startedAt   DateTime?
  completedAt DateTime?
  createdAt   DateTime    @default(now())
  updatedAt   DateTime    @updatedAt

  user  User  @relation(fields: [userId], references: [id])
  anime Anime @relation(fields: [animeId], references: [id])

  @@unique([userId, animeId])
  @@index([userId])
}
Source: prisma/schema.prisma:531-548
Each user can only have one watch record per anime (enforced by unique constraint).

Status Transitions

The progress system supports natural status transitions based on user behavior:

Status Definitions

User is actively consuming the media. This is the primary active state.
  • Anime/TV/Movie: Currently watching
  • Manga/Book: Currently reading
  • Game: Currently playing
User has finished the media in its entirety. This is a terminal state indicating full consumption.
Completion automatically triggers feed events and can unlock achievements/medals.
User has temporarily stopped but intends to continue. Progress is preserved.Can transition back to active state or forward to Completed/Dropped.
User has discontinued and doesn’t intend to continue. Progress is preserved but consumption ceased.
Dropped items can still be reviewed and are counted in user statistics.
User intends to start but hasn’t begun yet. This is the initial state.Common for:
  • Upcoming releases
  • Backlog management
  • Wishlist tracking

Progress Features

Unique Constraints

All progress models enforce a unique constraint on [userId, mediaId] to ensure:
  • One progress record per user per media item
  • No duplicate tracking entries
  • Clean update patterns
Example from AnimeProgress (prisma/schema.prisma:654):
@@unique([userId, animeId])

Automatic Timestamps

Every progress record maintains:
  • createdAt: When user first added the item
  • updatedAt: Last time status or progress changed

Legacy Models: Temporal Tracking

The legacy Watch/Read models track consumption timeframes:
  • startedAt: When user began watching/reading (nullable)
  • completedAt: When user finished (nullable)

Legacy Models: Granular Progress

Watch/Read models track precise position:
  • season: Current season number
  • episode: Current episode number
Allows resuming at exact position in episodic content.

Completion Tracking

Completion is tracked differently across models:

Progress Models

Status-based completion:
const isCompleted = progress.status === ProgressStatus.Completed;

Watch/Read Models

Multiple indicators:
const isCompleted = 
  watch.status === WatchStatus.Completed || 
  watch.completedAt !== null;

Integration with Feed System

Progress updates can trigger feed events to notify followers: | Event Type | Trigger | |-----------|---------|| | NewProgress | User updates status to Watching/Reading/Playing | | NewWatch | User marks anime/TV show as watching (legacy) | Feed Event Schema (prisma/schema.prisma:230-251):
enum FeedEventType {
  NewFollower
  NewFavorite
  NewList
  NewListItem
  NewReview
  NewWatch
  NewProgress
}

model FeedEvent {
  id        String        @id @default(uuid())
  type      FeedEventType
  userId    String
  metadata  Json?
  createdAt DateTime      @default(now())

  user      User       @relation(fields: [userId], references: [id], onDelete: Cascade)
  reactions Reaction[]

  @@index([userId, createdAt])
}

User Statistics

Progress data powers user statistics and achievements:

Completion Rate

Percentage of started items marked as completed

Total Watched

Count of anime/TV/movies with Completed status

Total Read

Count of manga/books with Completed status

Total Played

Count of games with Completed status

Current Watching

Count of items with Watching status

Backlog Size

Count of items with Planning status

Indexing Strategy

All progress models are indexed on userId for efficient queries:
@@index([userId])
This enables fast retrieval of:
  • All progress for a user
  • Status-filtered queries (e.g., “show me all watching”)
  • Aggregate statistics

Best Practices

Upsert Pattern

Use upsert operations to handle create/update seamlessly due to unique constraints

Cascade Deletes

Progress records cascade delete when user or media is deleted

Status Validation

Validate status transitions to prevent invalid states

Feed Events

Consider which status changes should trigger feed events

Migration from Legacy Models

If migrating from Watch/Read models to Progress models:
  1. Map WatchStatus/ReadStatus to ProgressStatus
  2. Preserve createdAt and updatedAt timestamps
  3. Store granular progress (episode/chapter) in metadata if needed
  4. Migrate temporal data (startedAt, completedAt) to metadata
  5. Maintain unique constraints on [userId, mediaId]

Build docs developers (and LLMs) love