Build the Data Layer
18 min read
Model Books and Reading Data
Model Books and Reading Data
A Readly user needs a private collection of books and a persistent reading position for each book.
Task
Add Book and ReadingProgress to the Prisma schema.
Use this model shape:
model Book {
id String @id @default(cuid())
userId String
title String
author String?
description String?
coverUrl String?
fileKey String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
readingProgress ReadingProgress?
bookmarks Bookmark[]
highlights Highlight[]
notes Note[]
@@index([userId])
@@index([userId, createdAt])
}
model ReadingProgress {
id String @id @default(cuid())
userId String
bookId String @unique
cfi String?
percentage Float @default(0)
completed Boolean @default(false)
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
book Book @relation(fields: [bookId], references: [id], onDelete: Cascade)
@@index([userId])
}
Make sure User also exposes the progress relation:
readingProgress ReadingProgress[]
Ownership Matters
userId is intentionally present on both Book and ReadingProgress. Later API handlers can verify that a resource belongs to the signed-in user before reading or changing it.
bookId is unique on ReadingProgress because each user should have one progress record for a book. The application will still verify user ownership when accessing the record.
Test
Run:
npx prisma format
npx prisma validate
Checkpoint
The schema now represents a user’s private books and persistent reading state.