training_data/packages/common/prisma/schema.prisma

514 lines
19 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
// generator zod {
// provider = "zod-prisma-types"
// output = "../src/generated" // (default) the directory where generated zod schemas will be saved
// createModelTypes = true
// createRelationValuesTypes = true
// writeNullishInModelTypes = true
// createPartialTypes = false
// useMultipleFiles = false
// useTypeAssertions = true
// }
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Taxonomy {
id String @id @default(cuid())
name String @unique
slug String @unique @map("slug")
deletedAt DateTime? @map("deleted_at")
createdAt DateTime @default(now()) @map("created_at")
terms Term[]
objectType String[] @map("object_type")
order Float? @map("order")
@@index([order, deletedAt])
@@map("taxonomy")
}
model Term {
id String @id @default(cuid())
name String
taxonomy Taxonomy? @relation(fields: [taxonomyId], references: [id])
taxonomyId String? @map("taxonomy_id")
order Float? @map("order")
description String?
parentId String? @map("parent_id")
parent Term? @relation("ChildParent", fields: [parentId], references: [id], onDelete: Cascade)
children Term[] @relation("ChildParent")
ancestors TermAncestry[] @relation("DescendantToAncestor")
descendants TermAncestry[] @relation("AncestorToDescendant")
domainId String? @map("domain_id")
domain Department? @relation("TermDom", fields: [domainId], references: [id])
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
deletedAt DateTime? @map("deleted_at")
createdBy String? @map("created_by")
depts Department[] @relation("department_term")
hasChildren Boolean? @default(false) @map("has_children")
courses Course[] @relation("course_term")
@@index([name]) // 对name字段建立索引以加快基于name的查找速度
@@index([parentId]) // 对parentId字段建立索引以加快基于parentId的查找速度
@@map("term")
}
model TermAncestry {
id String @id @default(cuid())
ancestorId String? @map("ancestor_id")
descendantId String @map("descendant_id")
relDepth Int @map("rel_depth")
ancestor Term? @relation("AncestorToDescendant", fields: [ancestorId], references: [id])
descendant Term @relation("DescendantToAncestor", fields: [descendantId], references: [id])
// 索引建议
@@index([ancestorId]) // 针对祖先的查询
@@index([descendantId]) // 针对后代的查询
@@index([ancestorId, descendantId]) // 组合索引,用于查询特定的祖先-后代关系
@@index([relDepth]) // 根据关系深度的查询
@@map("term_ancestry")
}
model Staff {
id String @id @default(cuid())
showname String? @map("showname")
username String @unique @map("username")
avatar String? @map("avatar")
password String? @map("password")
phoneNumber String? @unique @map("phone_number")
domainId String? @map("domain_id")
deptId String? @map("dept_id")
domain Department? @relation("DomainStaff", fields: [domainId], references: [id])
department Department? @relation("DeptStaff", fields: [deptId], references: [id])
order Float?
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
enabled Boolean? @default(true)
deletedAt DateTime? @map("deleted_at")
officerId String? @map("officer_id")
watchedPost Post[] @relation("post_watch_staff")
visits Visit[]
posts Post[]
sentMsgs Message[] @relation("message_sender")
receivedMsgs Message[] @relation("message_receiver")
enrollments Enrollment[]
courseReviews CourseReview[]
teachedCourses CourseInstructor[]
@@index([officerId])
@@index([deptId])
@@index([domainId])
@@index([username])
@@index([order])
@@map("staff")
}
model Department {
id String @id @default(cuid())
name String
order Float?
ancestors DeptAncestry[] @relation("DescendantToAncestor")
descendants DeptAncestry[] @relation("AncestorToDescendant")
parentId String? @map("parent_id")
parent Department? @relation("ChildParent", fields: [parentId], references: [id])
children Department[] @relation("ChildParent")
domainId String? @map("domain_id")
domainTerms Term[] @relation("TermDom")
deletedAt DateTime? @map("deleted_at")
isDomain Boolean? @default(false) @map("is_domain")
domainStaffs Staff[] @relation("DomainStaff")
deptStaffs Staff[] @relation("DeptStaff")
terms Term[] @relation("department_term")
watchedPost Post[] @relation("post_watch_dept")
hasChildren Boolean? @default(false) @map("has_children")
@@index([parentId])
@@index([isDomain])
@@index([name])
@@index([order])
@@map("department")
}
model DeptAncestry {
id String @id @default(cuid())
ancestorId String? @map("ancestor_id")
descendantId String @map("descendant_id")
relDepth Int @map("rel_depth")
ancestor Department? @relation("AncestorToDescendant", fields: [ancestorId], references: [id])
descendant Department @relation("DescendantToAncestor", fields: [descendantId], references: [id])
// 索引建议
@@index([ancestorId]) // 针对祖先的查询
@@index([descendantId]) // 针对后代的查询
@@index([ancestorId, descendantId]) // 组合索引,用于查询特定的祖先-后代关系
@@index([relDepth]) // 根据关系深度的查询
@@map("dept_ancestry")
}
model RoleMap {
id String @id @default(cuid())
objectId String @map("object_id")
roleId String @map("role_id")
domainId String? @map("domain_id")
objectType String @map("object_type")
role Role @relation(fields: [roleId], references: [id])
@@index([domainId])
@@index([objectId])
@@map("rolemap")
}
model Role {
id String @id @default(cuid())
name String @unique @map("name")
permissions String[] @default([]) @map("permissions")
roleMaps RoleMap[]
system Boolean? @default(false) @map("system")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
deletedAt DateTime? @map("deleted_at")
@@map("role")
}
model AppConfig {
id String @id @default(cuid())
slug String @unique
title String?
description String?
meta Json?
@@map("app_config")
}
model Post {
id String @id @default(cuid())
type String?
title String?
content String?
author Staff? @relation(fields: [authorId], references: [id])
authorId String?
domainId String?
referenceId String?
attachments String[] @default([])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
visits Visit[]
watchableStaffs Staff[] @relation("post_watch_staff")
watchableDepts Department[] @relation("post_watch_dept")
parentId String?
parent Post? @relation("PostChildren", fields: [parentId], references: [id])
children Post[] @relation("PostChildren")
deletedAt DateTime? @map("deleted_at")
Lecture Lecture? @relation(fields: [lectureId], references: [id])
lectureId String?
// 复合索引
@@index([type, domainId]) // 类型和域组合查询
@@index([authorId, type]) // 作者和类型组合查询
@@index([referenceId, type]) // 引用ID和类型组合查询
@@index([parentId, type]) // 父级帖子和创建时间索引
// 时间相关索引
@@index([createdAt]) // 按创建时间倒序索引
@@index([updatedAt]) // 按更新时间倒序索引
}
model Message {
id String @id @default(cuid())
url String?
intent String?
option Json?
senderId String? @map("sender_id")
messageType String?
sender Staff? @relation(name: "message_sender", fields: [senderId], references: [id])
title String?
content String?
receivers Staff[] @relation("message_receiver")
visits Visit[]
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime? @updatedAt @map("updated_at")
@@index([messageType, createdAt])
@@map("message")
}
model Visit {
id String @id @default(cuid())
visitType String? @map("visit_type")
visitorId String @map("visitor_id")
visitor Staff @relation(fields: [visitorId], references: [id])
postId String? @map("post_id")
post Post? @relation(fields: [postId], references: [id])
message Message? @relation(fields: [messageId], references: [id])
messageId String? @map("message_id")
views Int @default(1)
createdAt DateTime? @default(now()) @map("created_at")
updatedAt DateTime? @updatedAt @map("updated_at")
sourceIP String? @map("source_ip")
@@index([postId, visitType, visitorId])
@@index([messageId, visitType, visitorId])
@@map("visit")
}
model Course {
id String @id @default(cuid()) // 课程唯一标识符
title String // 课程标题
subTitle String? // 课程副标题(可选)
description String // 课程详细描述
thumbnail String? // 课程封面图片URL(可选)
level String // 课程难度等级
// 课程内容组织结构
terms Term[] @relation("course_term") // 课程学期
instructors CourseInstructor[] // 课程讲师团队
sections Section[] // 课程章节结构
enrollments Enrollment[] // 学生报名记录
reviews CourseReview[] // 学员课程评价
// 课程规划与目标设定
requirements String[] // 课程学习前置要求
objectives String[] // 具体的学习目标
skills String[] // 课程结束后可掌握的技能
audiences String[] // 目标受众群体描述
// 课程统计指标
totalDuration Int @default(0) // 课程总时长(分钟)
totalLectures Int @default(0) // 总课时数
averageRating Float @default(0) // 平均评分(1-5分)
numberOfReviews Int @default(0) // 评价总数
numberOfStudents Int @default(0) // 学习人数
completionRate Float @default(0) // 完课率(0-100%)
// 课程状态管理
status String // 课程状态(如:草稿/已发布/已归档)
isFeatured Boolean @default(false) // 是否为精选推荐课程
// 生命周期时间戳
createdAt DateTime @default(now()) // 创建时间
updatedAt DateTime @updatedAt // 最后更新时间
publishedAt DateTime? // 发布时间
archivedAt DateTime? // 归档时间
deletedAt DateTime? // 软删除时间
// 数据库索引优化
@@index([status]) // 课程状态索引,用于快速筛选
@@index([level]) // 难度等级索引,用于分类查询
@@index([isFeatured]) // 精选标记索引,用于首页推荐
}
model Section {
id String @id @default(cuid()) // 章节唯一标识符
title String // 章节标题
description String? // 章节描述(可选)
objectives String[] // 本章节的具体学习目标
order Float? @default(0) // 章节排序权重
// 关联关系
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
courseId String // 所属课程ID
lectures Lecture[] // 包含的所有课时
// 章节统计数据
totalDuration Int @default(0) // 本章节总时长(分钟)
totalLectures Int @default(0) // 本章节课时总数
// 时间管理
createdAt DateTime @default(now()) // 创建时间
updatedAt DateTime @updatedAt // 更新时间
deletedAt DateTime? // 软删除时间
@@index([courseId, order]) // 复合索引:用于按课程ID和顺序快速查询
}
model Lecture {
id String @id @default(cuid()) // 课时唯一标识符
title String // 课时标题
description String? // 课时描述(可选)
order Float? @default(0) // 课时排序权重
duration Int // 学习时长(分钟)
type String // 课时类型(video/article)
// 课时内容
content String? // Markdown格式文章内容
videoUrl String? // 视频URL地址
videoThumbnail String? // 视频封面图URL
// 关联内容
resources Resource[] // 课时附属资源
section Section @relation(fields: [sectionId], references: [id], onDelete: Cascade)
sectionId String // 所属章节ID
comments Post[] // 课时评论
progress LectureProgress[] // 学习进度记录
// 时间管理
publishedAt DateTime? // 发布时间
createdAt DateTime @default(now()) // 创建时间
updatedAt DateTime @updatedAt // 更新时间
deletedAt DateTime? // 软删除时间
@@index([sectionId, order]) // 章节内课时排序索引
@@index([type, publishedAt]) // 课时类型和发布时间复合索引
}
model Enrollment {
id String @id @default(cuid()) // 报名记录唯一标识符
status String // 报名状态(如:进行中/已完成/已过期)
// 关联关系
student Staff @relation(fields: [studentId], references: [id])
studentId String // 学员ID
course Course @relation(fields: [courseId], references: [id])
courseId String // 课程ID
progress LectureProgress[] // 课时学习进度记录
// 学习数据统计
completionRate Float @default(0) // 课程完成度(0-100%)
lastAccessedAt DateTime? // 最后访问时间
// 时间管理
createdAt DateTime @default(now()) // 报名时间
updatedAt DateTime @updatedAt // 更新时间
completedAt DateTime? // 完课时间
@@unique([studentId, courseId]) // 确保学员不会重复报名同一课程
@@index([status]) // 报名状态索引
@@index([completedAt]) // 完课时间索引
}
model LectureProgress {
id String @id @default(cuid()) // 进度记录唯一标识符
progress Float @default(0) // 完成进度(0-100%)
isCompleted Boolean @default(false) // 是否完成
// 关联关系
enrollment Enrollment @relation(fields: [enrollmentId], references: [id], onDelete: Cascade)
enrollmentId String // 报名记录ID
lecture Lecture @relation(fields: [lectureId], references: [id], onDelete: Cascade)
lectureId String // 课时ID
// 学习数据
lastPosition Int @default(0) // 视频播放位置(秒)
viewCount Int @default(0) // 观看次数
readCount Int @default(0) // 阅读次数
totalWatchTime Int @default(0) // 总观看时长(秒)
// 时间记录
lastWatchedAt DateTime? // 最后观看时间
createdAt DateTime @default(now()) // 创建时间
updatedAt DateTime @updatedAt // 更新时间
@@unique([enrollmentId, lectureId]) // 确保每个报名只有一条课时进度
@@index([isCompleted]) // 完成状态索引
@@index([lastWatchedAt]) // 最后观看时间索引
}
model CourseInstructor {
course Course @relation(fields: [courseId], references: [id])
courseId String // 课程ID
instructor Staff @relation(fields: [instructorId], references: [id])
instructorId String // 讲师ID
role String // 讲师角色
createdAt DateTime @default(now()) // 创建时间
order Float? @default(0) // 讲师显示顺序
@@id([courseId, instructorId]) // 联合主键
}
model CourseReview {
id String @id @default(cuid()) // 评价唯一标识符
rating Int // 评分(1-5星)
content String? // 评价内容
student Staff @relation(fields: [studentId], references: [id])
studentId String // 评价学员ID
course Course @relation(fields: [courseId], references: [id])
courseId String // 课程ID
helpfulCount Int @default(0) // 评价点赞数
createdAt DateTime @default(now()) // 评价时间
updatedAt DateTime @updatedAt // 更新时间
@@unique([studentId, courseId]) // 确保学员对同一课程只能评价一次
@@index([rating]) // 评分索引
}
model Resource {
id String @id @default(cuid()) // 资源唯一标识符
title String // 资源标题
description String? // 资源描述
type String // 资源类型
url String // 资源URL
fileType String? // 文件MIME类型
fileSize Int? // 文件大小(bytes)
lecture Lecture @relation(fields: [lectureId], references: [id], onDelete: Cascade)
lectureId String // 所属课时ID
downloadCount Int @default(0) // 下载次数
createdAt DateTime @default(now()) // 创建时间
updatedAt DateTime @updatedAt // 更新时间
@@index([lectureId, type]) // 课时资源类型复合索引
}
model Node {
id String @id @default(cuid())
title String
description String?
type String
// 节点之间的关系
sourceEdges NodeEdge[] @relation("from_node")
targetEdges NodeEdge[] @relation("to_node")
style Json?
position Json? // 存储节点在画布中的位置 {x: number, y: number}
data Json?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// 节点之间的关系
model NodeEdge {
id String @id @default(cuid())
// 关系的起点和终点
source Node @relation("from_node", fields: [sourceId], references: [id], onDelete: Cascade)
sourceId String
target Node @relation("to_node", fields: [targetId], references: [id], onDelete: Cascade)
targetId String
// 关系属性
type String?
label String?
description String?
// 自定义边的样式(可选)
style Json? // 存储边的样式,如 {color: string, strokeWidth: number}
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([sourceId, targetId, type])
@@index([sourceId])
@@index([targetId])
}