feat: add course catalog, enrollment, progress tracking, quizzes, and reviews
Backend changes: - Add Enrollment and LessonProgress models to track user progress - Add UserRole enum (USER, MODERATOR, ADMIN) - Add course verification and moderation fields - New CatalogModule: public course browsing, publishing, verification - New EnrollmentModule: enroll, progress tracking, quiz submission, reviews - Add quiz generation endpoint to LessonsController Frontend changes: - Redesign course viewer: proper course UI with lesson navigation, progress bar - Add beautiful typography styles for course content (prose-course) - Fix first-login bug with token exchange retry logic - New pages: /catalog (public courses), /catalog/[id] (course details), /learning (enrollments) - Add LessonQuiz component with scoring and results - Update sidebar navigation: add Catalog and My Learning links - Add publish/verify buttons in course editor - Integrate enrollment progress tracking with backend All courses now support: sequential progression, quiz tests, reviews, ratings, author verification badges, and full marketplace publishing workflow. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@ -30,10 +30,15 @@ model User {
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
// Role
|
||||
role UserRole @default(USER)
|
||||
|
||||
// Relations
|
||||
settings UserSettings?
|
||||
subscription Subscription?
|
||||
courses Course[] @relation("AuthoredCourses")
|
||||
enrollments Enrollment[]
|
||||
lessonProgress LessonProgress[]
|
||||
purchases Purchase[]
|
||||
reviews Review[]
|
||||
generations CourseGeneration[]
|
||||
@ -65,6 +70,12 @@ model UserSettings {
|
||||
@@map("user_settings")
|
||||
}
|
||||
|
||||
enum UserRole {
|
||||
USER
|
||||
MODERATOR
|
||||
ADMIN
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Subscription & Payments
|
||||
// ============================================
|
||||
@ -113,7 +124,9 @@ model Subscription {
|
||||
enum CourseStatus {
|
||||
DRAFT
|
||||
GENERATING
|
||||
PENDING_REVIEW
|
||||
PUBLISHED
|
||||
REJECTED
|
||||
ARCHIVED
|
||||
}
|
||||
|
||||
@ -130,11 +143,14 @@ model Course {
|
||||
// Status
|
||||
status CourseStatus @default(DRAFT)
|
||||
|
||||
// Marketplace (future)
|
||||
// Marketplace
|
||||
isPublished Boolean @default(false) @map("is_published")
|
||||
price Decimal? @db.Decimal(10, 2) // null = private course
|
||||
price Decimal? @db.Decimal(10, 2) // null = free course
|
||||
currency String @default("USD")
|
||||
|
||||
// Author verification — author checked the content and vouches for quality
|
||||
isVerified Boolean @default(false) @map("is_verified")
|
||||
|
||||
// Categorization
|
||||
categoryId String? @map("category_id")
|
||||
tags String[] @default([])
|
||||
@ -155,10 +171,15 @@ model Course {
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
// Moderation
|
||||
moderationNote String? @db.Text @map("moderation_note")
|
||||
moderatedAt DateTime? @map("moderated_at")
|
||||
|
||||
// Relations
|
||||
author User @relation("AuthoredCourses", fields: [authorId], references: [id], onDelete: Cascade)
|
||||
category Category? @relation(fields: [categoryId], references: [id])
|
||||
chapters Chapter[]
|
||||
enrollments Enrollment[]
|
||||
purchases Purchase[]
|
||||
reviews Review[]
|
||||
generation CourseGeneration?
|
||||
@ -360,3 +381,53 @@ model Review {
|
||||
@@index([courseId])
|
||||
@@map("reviews")
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Enrollment & Progress
|
||||
// ============================================
|
||||
|
||||
model Enrollment {
|
||||
id String @id @default(uuid())
|
||||
userId String @map("user_id")
|
||||
courseId String @map("course_id")
|
||||
|
||||
// Progress
|
||||
progress Int @default(0) // 0-100
|
||||
completedAt DateTime? @map("completed_at")
|
||||
|
||||
// Certificate
|
||||
certificateUrl String? @map("certificate_url")
|
||||
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
// Relations
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
|
||||
lessons LessonProgress[]
|
||||
|
||||
@@unique([userId, courseId])
|
||||
@@index([userId])
|
||||
@@index([courseId])
|
||||
@@map("enrollments")
|
||||
}
|
||||
|
||||
model LessonProgress {
|
||||
id String @id @default(uuid())
|
||||
userId String @map("user_id")
|
||||
enrollmentId String @map("enrollment_id")
|
||||
lessonId String @map("lesson_id")
|
||||
|
||||
completedAt DateTime? @map("completed_at")
|
||||
quizScore Int? @map("quiz_score") // 0-100
|
||||
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
// Relations
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
enrollment Enrollment @relation(fields: [enrollmentId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([userId, lessonId])
|
||||
@@index([enrollmentId])
|
||||
@@map("lesson_progress")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user