generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } model User { id String @id @default(uuid()) @db.Uuid authUserId String? @unique @map("auth_user_id") @db.Uuid email String @unique name String? authRole String? @map("auth_role") primaryOrganizationId String? @map("primary_organization_id") @db.Uuid primaryOrganizationName String? @map("primary_organization_name") primaryOrganizationType String? @map("primary_organization_type") department String? position String? createdAt DateTime @default(now()) @db.Timestamptz(3) updatedAt DateTime @updatedAt @db.Timestamptz(3) courses Course[] @relation("CourseTeacher") progress CourseStudentProgress[] weekProgress CourseStudentWeekProgress[] groupMemberships StudentGroupMember[] enrollments StudentEnrollment[] studentChatThreads ChatThread[] @relation("ChatThreadStudent") assignedChatThreads ChatThread[] @relation("ChatThreadInstructor") chatMessages ChatMessage[] platformControlSessions PlatformControlSession[] platformControlQueueEntries PlatformControlQueueEntry[] studioRepositories StudioRepository[] customModuleRepositories StudentCustomModuleRepository[] savedMaps StudentSavedMap[] customModules StudentCustomModule[] teamCustomModules TeamCustomModule[] @relation("TeamCustomModuleCreator") submissionScores SubmissionScore[] submissionTotalScores SubmissionTotalScore[] @@index([authRole]) @@index([primaryOrganizationId]) @@map("users") } model StudentEnrollment { id String @id @default(uuid()) @db.Uuid userId String @map("user_id") @db.Uuid courseId String @map("course_id") @db.Uuid organizationId String? @map("organization_id") @db.Uuid organizationName String @map("organization_name") status String @default("ACTIVE") removedAt DateTime? @map("removed_at") @db.Timestamptz(3) createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) user User @relation(fields: [userId], references: [id], onDelete: Cascade) course Course @relation(fields: [courseId], references: [id], onDelete: Cascade) @@unique([userId, courseId]) @@index([courseId, status]) @@index([organizationId, status]) @@index([organizationName, status]) @@map("student_enrollments") } model StudentGroup { id String @id @default(uuid()) @db.Uuid organizationId String? @map("organization_id") @db.Uuid organizationName String @map("organization_name") name String week Int @default(1) status String @default("진행중") platformName String? @map("platform_name") instructorPlatformId String? @map("instructor_platform_id") @db.Uuid createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) members StudentGroupMember[] instructorPlatform InstructorPlatform? @relation(fields: [instructorPlatformId], references: [id], onDelete: SetNull) platformControlSessions PlatformControlSession[] platformControlQueueEntries PlatformControlQueueEntry[] curriculumSettings InstructorCurriculumSetting[] teamStudioRepositories TeamStudioRepository[] teamCustomModuleRepositories TeamCustomModuleRepository[] teamCustomModules TeamCustomModule[] @@unique([organizationName, name]) @@index([organizationId]) @@index([organizationName]) @@index([instructorPlatformId]) @@map("student_groups") } model InstructorPlatform { id String @id @default(uuid()) @db.Uuid organizationId String? @map("organization_id") @db.Uuid organizationName String @map("organization_name") platformId String @map("platform_id") @db.Uuid displayName String @map("display_name") instanceNo Int @map("instance_no") status String @default("대기") battery Int @default(100) uptimeMinutes Int @default(0) @map("uptime_minutes") speedMeters Decimal @default(0) @map("speed_meters") @db.Decimal(6, 2) errorCount Int @default(0) @map("error_count") emergencyStop Boolean @default(false) @map("emergency_stop") vehicleType String @default("MK-mini") @map("vehicle_type") wheelbaseMeters Decimal @default(0.325) @map("wheelbase_meters") @db.Decimal(6, 3) maxSpeedMetersPerSecond Decimal @default(7.0) @map("max_speed_meters_per_second") @db.Decimal(6, 2) maxSteeringAngleDegrees Decimal @default(30) @map("max_steering_angle_degrees") @db.Decimal(6, 2) sensors Json @default("[]") drivers Json @default("[]") algorithms Json @default("{}") studioSettingsOverride Json? @map("studio_settings_override") controlDurationMinutes Int @default(30) @map("control_duration_minutes") controlWarningMinutes Int @default(5) @map("control_warning_minutes") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) platform Platform @relation(fields: [platformId], references: [id], onDelete: Restrict) assignedGroups StudentGroup[] controlSessions PlatformControlSession[] controlQueueEntries PlatformControlQueueEntry[] @@unique([organizationName, displayName]) @@unique([organizationName, platformId, instanceNo]) @@index([organizationId]) @@index([organizationName]) @@index([platformId]) @@map("instructor_platforms") } model StudentGroupMember { id String @id @default(uuid()) @db.Uuid groupId String @map("group_id") @db.Uuid userId String @map("user_id") @db.Uuid createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) group StudentGroup @relation(fields: [groupId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([groupId, userId]) @@index([userId]) @@map("student_group_members") } model Course { id String @id @default(uuid()) @db.Uuid slug String @unique title String subtitle String? description String? organizationName String @map("organization_name") teacherId String @map("teacher_id") @db.Uuid isActive Boolean @default(true) @map("is_active") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) teacher User @relation("CourseTeacher", fields: [teacherId], references: [id], onDelete: Restrict) weeks CourseWeek[] platforms CoursePlatform[] studentProgress CourseStudentProgress[] studentWeekProgress CourseStudentWeekProgress[] chatThreads ChatThread[] enrollments StudentEnrollment[] instructorCurriculumSettings InstructorCurriculumSetting[] instructorCurriculumWeekOverrides InstructorCurriculumWeekOverride[] environmentProfiles CourseEnvironmentProfile[] maps CourseMap[] weekMaps CourseWeekMap[] savedMaps StudentSavedMap[] customModules StudentCustomModule[] teamCustomModules TeamCustomModule[] submissionScores SubmissionScore[] submissionTotalScores SubmissionTotalScore[] @@index([isActive]) @@index([teacherId]) @@map("courses") } model CourseEnvironmentProfile { id String @id @default(uuid()) @db.Uuid courseId String @map("course_id") @db.Uuid week Int platformKey String @default("futuredrive-local-pc") @map("platform_key") profileType String @map("profile_type") name String config Json enabled Boolean @default(true) createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) course Course @relation(fields: [courseId], references: [id], onDelete: Cascade) @@unique([courseId, week, platformKey]) @@index([courseId, week]) @@index([profileType]) @@map("course_environment_profiles") } model CourseMap { id String @id @default(uuid()) @db.Uuid courseId String @map("course_id") @db.Uuid key String name String description String? platformKey String @default("NAV2") @map("platform_key") worldFile String @default("empty_world.world") @map("world_file") viewerModel String @default("turtlebot3_world") @map("viewer_model") layout Json @default("{\"version\":1,\"objects\":[]}") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) course Course @relation(fields: [courseId], references: [id], onDelete: Cascade) @@unique([courseId, key]) @@index([courseId, platformKey]) @@map("course_maps") } model CourseWeekMap { id String @id @default(uuid()) @db.Uuid courseId String @map("course_id") @db.Uuid week Int mapKey String @map("map_key") sortOrder Int @default(0) @map("sort_order") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) course Course @relation(fields: [courseId], references: [id], onDelete: Cascade) @@unique([courseId, week, mapKey]) @@index([courseId, week]) @@map("course_week_maps") } model StudentSavedMap { id String @id @default(uuid()) @db.Uuid userId String @map("user_id") @db.Uuid courseId String @map("course_id") @db.Uuid week Int name String sourceMapKey String @map("source_map_key") worldFile String @map("world_file") viewerModel String @map("viewer_model") yamlPath String @map("yaml_path") pgmPath String @map("pgm_path") yamlUrl String? @map("yaml_url") pgmUrl String? @map("pgm_url") previewPgm String? @map("preview_pgm") databasePath String? @map("database_path") databaseUrl String? @map("database_url") runtimeKind String @default("SIMULATION") @map("runtime_kind") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) user User @relation(fields: [userId], references: [id], onDelete: Cascade) course Course @relation(fields: [courseId], references: [id], onDelete: Cascade) @@unique([userId, courseId, week, yamlPath]) @@index([userId, courseId, week, createdAt]) @@index([userId, courseId, week, runtimeKind]) @@map("student_saved_maps") } model StudentCustomModule { id String @id @default(uuid()) @db.Uuid userId String @map("user_id") @db.Uuid courseId String @map("course_id") @db.Uuid week Int sortOrder Int @map("sort_order") category String name String folderName String @map("folder_name") dockerImage String? @map("docker_image") packageName String @map("package_name") launchFile String @map("launch_file") runtimeTarget String @default("LOCAL") @map("runtime_target") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) user User @relation(fields: [userId], references: [id], onDelete: Cascade) course Course @relation(fields: [courseId], references: [id], onDelete: Cascade) repository StudentCustomModuleRepository? @@unique([userId, courseId, week, folderName, runtimeTarget]) @@index([userId, courseId, week, sortOrder]) @@index([userId, courseId, week, runtimeTarget, sortOrder]) @@map("student_custom_modules") } model TeamCustomModule { id String @id @default(uuid()) @db.Uuid groupId String @map("group_id") @db.Uuid creatorId String @map("creator_id") @db.Uuid courseId String @map("course_id") @db.Uuid week Int sortOrder Int @map("sort_order") category String name String folderName String @map("folder_name") dockerImage String? @map("docker_image") packageName String @map("package_name") launchFile String @map("launch_file") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) group StudentGroup @relation(fields: [groupId], references: [id], onDelete: Cascade) creator User @relation("TeamCustomModuleCreator", fields: [creatorId], references: [id], onDelete: Cascade) course Course @relation(fields: [courseId], references: [id], onDelete: Cascade) repository TeamCustomModuleRepository? @@unique([groupId, courseId, week, folderName]) @@index([groupId, courseId, week, sortOrder]) @@map("team_custom_modules") } model StudentCustomModuleRepository { id String @id @default(uuid()) @db.Uuid userId String @map("user_id") @db.Uuid customModuleId String @unique @map("custom_module_id") @db.Uuid repoOwner String @map("repo_owner") repoName String @map("repo_name") repositoryUrl String @map("repository_url") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) user User @relation(fields: [userId], references: [id], onDelete: Cascade) customModule StudentCustomModule @relation(fields: [customModuleId], references: [id], onDelete: Cascade) @@index([userId]) @@index([repoOwner, repoName]) @@map("student_custom_module_repositories") } model TeamCustomModuleRepository { id String @id @default(uuid()) @db.Uuid groupId String @map("group_id") @db.Uuid customModuleId String @unique @map("custom_module_id") @db.Uuid repoOwner String @map("repo_owner") repoName String @map("repo_name") repositoryUrl String @map("repository_url") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) group StudentGroup @relation(fields: [groupId], references: [id], onDelete: Cascade) customModule TeamCustomModule @relation(fields: [customModuleId], references: [id], onDelete: Cascade) @@index([groupId]) @@index([repoOwner, repoName]) @@map("team_custom_module_repositories") } model InstructorCurriculumSetting { id String @id @default(uuid()) @db.Uuid organizationId String? @map("organization_id") @db.Uuid organizationName String @map("organization_name") groupId String? @map("group_id") @db.Uuid courseId String @map("course_id") @db.Uuid activeWeek Int @default(1) @map("active_week") activeLearningStep String? @map("active_learning_step") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) course Course @relation(fields: [courseId], references: [id], onDelete: Restrict) group StudentGroup? @relation(fields: [groupId], references: [id], onDelete: Cascade) @@index([organizationId]) @@index([organizationName]) @@index([groupId]) @@index([courseId]) @@map("instructor_curriculum_settings") } model InstructorCurriculumWeekOverride { id String @id @default(uuid()) @db.Uuid organizationId String? @map("organization_id") @db.Uuid organizationName String @map("organization_name") courseId String @map("course_id") @db.Uuid week Int tagLabel String? @map("tag_label") title String? duration String? overview String? deliverable String? requiresSourceSubmission Boolean? @default(true) @map("requires_source_submission") isTeamProject Boolean? @default(false) @map("is_team_project") learningSteps Json? @map("learning_steps") topics Json? topicDetails Json? @map("topic_details") topicVideoUrls Json? @map("topic_video_urls") practiceContents Json? @map("practice_contents") disabledModuleIds Json? @map("disabled_module_ids") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) course Course @relation(fields: [courseId], references: [id], onDelete: Cascade) @@unique([organizationName, courseId, week]) @@index([organizationId]) @@index([organizationName]) @@index([courseId]) @@map("instructor_curriculum_week_overrides") } model Platform { id String @id @default(uuid()) @db.Uuid platformKey String @unique @map("platform_key") displayName String @map("display_name") description String organizationName String @map("organization_name") iconKey String @map("icon_key") isActive Boolean @default(true) @map("is_active") curriculumTagOnly Boolean @default(false) @map("curriculum_tag_only") vehicleType String @default("MK-mini") @map("vehicle_type") wheelbaseMeters Decimal @default(0.325) @map("wheelbase_meters") @db.Decimal(6, 3) maxSpeedMetersPerSecond Decimal @default(7.0) @map("max_speed_meters_per_second") @db.Decimal(6, 2) maxSteeringAngleDegrees Decimal @default(30) @map("max_steering_angle_degrees") @db.Decimal(6, 2) sensors Json @default("[]") drivers Json @default("[]") algorithms Json @default("{}") defaultStudioSettings Json @default("{\"workspaceRoot\":\"~/autonomy-studio/workspaces\",\"giteaBaseUrl\":\"http://localhost:3000\",\"giteaOwner\":\"student\"}") @map("default_studio_settings") controlDurationMinutes Int @default(30) @map("control_duration_minutes") controlWarningMinutes Int @default(5) @map("control_warning_minutes") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) courses CoursePlatform[] instructorPlatforms InstructorPlatform[] controlSessions PlatformControlSession[] controlQueueEntries PlatformControlQueueEntry[] @@index([organizationName]) @@index([isActive]) @@map("platforms") } model CoursePlatform { id String @id @default(uuid()) @db.Uuid courseId String @map("course_id") @db.Uuid platformId String @map("platform_id") @db.Uuid status String action String state String sortOrder Int @default(0) @map("sort_order") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) course Course @relation(fields: [courseId], references: [id], onDelete: Cascade) platform Platform @relation(fields: [platformId], references: [id], onDelete: Restrict) @@unique([courseId, platformId]) @@index([courseId, sortOrder]) @@index([platformId]) @@map("course_platforms") } model PlatformControlSession { id String @id @default(uuid()) @db.Uuid organizationId String? @map("organization_id") @db.Uuid organizationName String @map("organization_name") platformId String? @map("platform_id") @db.Uuid instructorPlatformId String? @map("instructor_platform_id") @db.Uuid holderUserId String @map("holder_user_id") @db.Uuid groupId String? @map("group_id") @db.Uuid status String @default("ACTIVE") startedAt DateTime @default(now()) @map("started_at") @db.Timestamptz(3) endsAt DateTime @map("ends_at") @db.Timestamptz(3) warningAt DateTime @map("warning_at") @db.Timestamptz(3) warningSentAt DateTime? @map("warning_sent_at") @db.Timestamptz(3) extensionCount Int @default(0) @map("extension_count") releasedAt DateTime? @map("released_at") @db.Timestamptz(3) endReason String? @map("end_reason") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) platform Platform? @relation(fields: [platformId], references: [id], onDelete: Restrict) instructorPlatform InstructorPlatform? @relation(fields: [instructorPlatformId], references: [id], onDelete: Restrict) holderUser User @relation(fields: [holderUserId], references: [id], onDelete: Cascade) group StudentGroup? @relation(fields: [groupId], references: [id], onDelete: SetNull) @@index([organizationId]) @@index([organizationName]) @@index([platformId, status]) @@index([instructorPlatformId, status]) @@index([holderUserId, status]) @@index([endsAt, status]) @@map("platform_control_sessions") } model PlatformControlQueueEntry { id String @id @default(uuid()) @db.Uuid organizationId String? @map("organization_id") @db.Uuid organizationName String @map("organization_name") platformId String? @map("platform_id") @db.Uuid instructorPlatformId String? @map("instructor_platform_id") @db.Uuid userId String @map("user_id") @db.Uuid groupId String? @map("group_id") @db.Uuid status String @default("WAITING") requestedAt DateTime @default(now()) @map("requested_at") @db.Timestamptz(3) grantedAt DateTime? @map("granted_at") @db.Timestamptz(3) canceledAt DateTime? @map("canceled_at") @db.Timestamptz(3) createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) platform Platform? @relation(fields: [platformId], references: [id], onDelete: Restrict) instructorPlatform InstructorPlatform? @relation(fields: [instructorPlatformId], references: [id], onDelete: Restrict) user User @relation(fields: [userId], references: [id], onDelete: Cascade) group StudentGroup? @relation(fields: [groupId], references: [id], onDelete: SetNull) @@index([organizationId]) @@index([organizationName]) @@index([platformId, status, requestedAt]) @@index([instructorPlatformId, status, requestedAt]) @@index([userId, status]) @@map("platform_control_queue_entries") } model CourseStudentProgress { id String @id @default(uuid()) @db.Uuid courseId String @map("course_id") @db.Uuid userId String @map("user_id") @db.Uuid completedWeeks Int @default(0) @map("completed_weeks") totalWeeks Int @default(0) @map("total_weeks") learningHours Int @default(0) @map("learning_hours") commitCount Int @default(0) @map("commit_count") averageScore Int @default(0) @map("average_score") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) course Course @relation(fields: [courseId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([courseId, userId]) @@index([userId]) @@map("course_student_progress") } model CourseStudentWeekProgress { id String @id @default(uuid()) @db.Uuid courseId String @map("course_id") @db.Uuid userId String @map("user_id") @db.Uuid week Int submittedAt DateTime? @map("submitted_at") @db.Timestamptz(3) commitCount Int @default(0) @map("commit_count") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) course Course @relation(fields: [courseId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([courseId, userId, week]) @@index([userId]) @@map("course_student_week_progress") } model CourseWeek { id String @id @default(uuid()) @db.Uuid courseId String @map("course_id") @db.Uuid week Int title String tags String[] progress Int @default(0) state String duration String github String overview String deliverable String requiresSourceSubmission Boolean @default(true) @map("requires_source_submission") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) course Course @relation(fields: [courseId], references: [id], onDelete: Cascade) topics CourseWeekTopic[] practices CourseWeekPractice[] references CourseWeekReference[] modules CourseWeekModule[] chatThreads ChatThread[] submissionScores SubmissionScore[] submissionTotalScores SubmissionTotalScore[] @@unique([courseId, week]) @@index([courseId]) @@map("course_weeks") } model CourseWeekModule { id String @id @default(uuid()) @db.Uuid weekId String @map("week_id") @db.Uuid sortOrder Int @map("sort_order") category String name String folderName String @map("folder_name") templateRepositoryUrl String? @map("template_repository_url") sourceType String @default("GIT") @map("source_type") prebuiltArtifacts Json @default("[]") @map("prebuilt_artifacts") defaultParameters Json @default("[]") @map("default_parameters") dockerImage String? @map("docker_image") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) week CourseWeek @relation(fields: [weekId], references: [id], onDelete: Cascade) studioRepositories StudioRepository[] teamStudioRepositories TeamStudioRepository[] submissionScores SubmissionScore[] @@unique([weekId, folderName]) @@unique([weekId, sortOrder]) @@index([weekId]) @@map("course_week_modules") } model StudioRepository { id String @id @default(uuid()) @db.Uuid userId String @map("user_id") @db.Uuid weekId String @map("week_id") @db.Uuid moduleId String @map("module_id") @db.Uuid repoOwner String @map("repo_owner") repoName String @map("repo_name") repositoryUrl String @map("repository_url") templateRepositoryUrl String @map("template_repository_url") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) user User @relation(fields: [userId], references: [id], onDelete: Cascade) module CourseWeekModule @relation(fields: [moduleId], references: [id], onDelete: Cascade) @@unique([userId, moduleId]) @@index([weekId]) @@index([repoOwner, repoName]) @@map("studio_repositories") } model TeamStudioRepository { id String @id @default(uuid()) @db.Uuid groupId String @map("group_id") @db.Uuid weekId String @map("week_id") @db.Uuid moduleId String @map("module_id") @db.Uuid repoOwner String @map("repo_owner") repoName String @map("repo_name") repositoryUrl String @map("repository_url") templateRepositoryUrl String @map("template_repository_url") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) group StudentGroup @relation(fields: [groupId], references: [id], onDelete: Cascade) module CourseWeekModule @relation(fields: [moduleId], references: [id], onDelete: Cascade) @@unique([groupId, moduleId]) @@index([weekId]) @@index([repoOwner, repoName]) @@map("team_studio_repositories") } model SubmissionScore { id String @id @default(uuid()) @db.Uuid courseId String @map("course_id") @db.Uuid weekId String @map("week_id") @db.Uuid moduleId String @map("module_id") @db.Uuid studentId String @map("student_id") @db.Uuid score Int @default(0) createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) course Course @relation(fields: [courseId], references: [id], onDelete: Cascade) week CourseWeek @relation(fields: [weekId], references: [id], onDelete: Cascade) module CourseWeekModule @relation(fields: [moduleId], references: [id], onDelete: Cascade) student User @relation(fields: [studentId], references: [id], onDelete: Cascade) @@unique([studentId, moduleId]) @@index([courseId]) @@index([weekId]) @@index([moduleId]) @@map("submission_scores") } model SubmissionTotalScore { id String @id @default(uuid()) @db.Uuid courseId String @map("course_id") @db.Uuid weekId String @map("week_id") @db.Uuid studentId String @map("student_id") @db.Uuid score Int @default(0) createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) course Course @relation(fields: [courseId], references: [id], onDelete: Cascade) week CourseWeek @relation(fields: [weekId], references: [id], onDelete: Cascade) student User @relation(fields: [studentId], references: [id], onDelete: Cascade) @@unique([studentId, weekId]) @@index([courseId]) @@index([weekId]) @@map("submission_total_scores") } model CourseWeekTopic { id String @id @default(uuid()) @db.Uuid weekId String @map("week_id") @db.Uuid title String detail String sortOrder Int @map("sort_order") week CourseWeek @relation(fields: [weekId], references: [id], onDelete: Cascade) @@unique([weekId, sortOrder]) @@index([weekId]) @@map("course_week_topics") } model CourseWeekPractice { id String @id @default(uuid()) @db.Uuid weekId String @map("week_id") @db.Uuid title String description String sortOrder Int @map("sort_order") week CourseWeek @relation(fields: [weekId], references: [id], onDelete: Cascade) @@unique([weekId, sortOrder]) @@index([weekId]) @@map("course_week_practices") } model CourseWeekReference { id String @id @default(uuid()) @db.Uuid weekId String @map("week_id") @db.Uuid kind String @default("REFERENCE") title String originalFileName String @map("original_file_name") storedFileName String @map("stored_file_name") contentType String? @map("content_type") fileSizeBytes Int @default(0) @map("file_size_bytes") sortOrder Int @default(0) @map("sort_order") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) week CourseWeek @relation(fields: [weekId], references: [id], onDelete: Cascade) @@unique([weekId, storedFileName]) @@index([weekId]) @@index([weekId, kind]) @@map("course_week_references") } enum ChatThreadType { AI INSTRUCTOR MIXED } enum ChatThreadStatus { OPEN WAITING_INSTRUCTOR RESOLVED ARCHIVED } enum ChatSenderType { STUDENT AI INSTRUCTOR SYSTEM } enum ChatContentFormat { TEXT MARKDOWN } enum ChatMessageStatus { ACTIVE CANCELED } enum AiChatRunStatus { SUCCEEDED FAILED } model ChatThread { id String @id @default(uuid()) @db.Uuid courseId String @map("course_id") @db.Uuid weekId String? @map("week_id") @db.Uuid studentId String @map("student_id") @db.Uuid assignedInstructorId String? @map("assigned_instructor_id") @db.Uuid type ChatThreadType status ChatThreadStatus @default(OPEN) title String? createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3) lastMessageAt DateTime @default(now()) @map("last_message_at") @db.Timestamptz(3) course Course @relation(fields: [courseId], references: [id], onDelete: Cascade) week CourseWeek? @relation(fields: [weekId], references: [id], onDelete: SetNull) student User @relation("ChatThreadStudent", fields: [studentId], references: [id], onDelete: Cascade) assignedInstructor User? @relation("ChatThreadInstructor", fields: [assignedInstructorId], references: [id], onDelete: SetNull) messages ChatMessage[] @@index([courseId, type, lastMessageAt]) @@index([studentId, type, lastMessageAt]) @@index([weekId]) @@index([assignedInstructorId]) @@map("chat_threads") } model ChatMessage { id String @id @default(uuid()) @db.Uuid threadId String @map("thread_id") @db.Uuid senderType ChatSenderType @map("sender_type") senderUserId String? @map("sender_user_id") @db.Uuid content String contentFormat ChatContentFormat @default(TEXT) @map("content_format") status ChatMessageStatus @default(ACTIVE) metadata Json? createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) canceledAt DateTime? @map("canceled_at") @db.Timestamptz(3) deletedAt DateTime? @map("deleted_at") @db.Timestamptz(3) thread ChatThread @relation(fields: [threadId], references: [id], onDelete: Cascade) senderUser User? @relation(fields: [senderUserId], references: [id], onDelete: SetNull) aiRun AiChatRun? @@index([threadId, createdAt]) @@index([threadId, status, createdAt]) @@index([senderUserId]) @@map("chat_messages") } model AiChatRun { id String @id @default(uuid()) @db.Uuid messageId String @unique @map("message_id") @db.Uuid model String promptTokens Int? @map("prompt_tokens") completionTokens Int? @map("completion_tokens") totalTokens Int? @map("total_tokens") latencyMs Int? @map("latency_ms") status AiChatRunStatus error String? createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3) message ChatMessage @relation(fields: [messageId], references: [id], onDelete: Cascade) @@index([status, createdAt]) @@map("ai_chat_runs") }