00a3904eba
- 新增 Donation 模型/迁移/后端 API(GET,POST /donations) - 新增前端 /donate 页:收款码+感谢留言+感谢墙 - 会员页/技能广场/用量包 下架付费,改免费开放+赞助入口 - 沙箱用量耗尽引导至 /donate 赞助 - 导航与页脚新增 赞助/联盟返佣 入口,补充 i18n
733 lines
22 KiB
Plaintext
Executable File
733 lines
22 KiB
Plaintext
Executable File
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "mysql"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
model User {
|
|
id Int @id @default(autoincrement())
|
|
phone String? @unique
|
|
email String? @unique
|
|
passwordHash String?
|
|
nickname String?
|
|
avatar String?
|
|
bio String?
|
|
status UserStatus @default(ACTIVE)
|
|
memberPlan MemberPlan @default(FREE)
|
|
memberExpire DateTime?
|
|
sandboxDaily Int @default(5)
|
|
followerCount Int @default(0)
|
|
followingCount Int @default(0)
|
|
postCount Int @default(0)
|
|
lastLoginAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
deletedAt DateTime?
|
|
username String? @unique
|
|
sandboxExtra Int @default(0)
|
|
circleMemberships CircleMember[]
|
|
createdCircles Circle[] @relation("CircleCreator")
|
|
comments Comment[]
|
|
following Follow[] @relation("Follower")
|
|
followers Follow[] @relation("Following")
|
|
learnRecords LearnRecord[]
|
|
notifications Notification[]
|
|
orders Order[]
|
|
organizationMemberships OrganizationMember[]
|
|
postLikes PostLike[]
|
|
posts Post[]
|
|
practiceSubmissions PracticeSubmission[]
|
|
promptFavorites PromptFavorite[]
|
|
prompts Prompt[]
|
|
sandboxSessions SandboxSession[]
|
|
subscriptions Subscription[]
|
|
userSkills UserSkill[]
|
|
|
|
@@map("users")
|
|
}
|
|
|
|
model Category {
|
|
id Int @id @default(autoincrement())
|
|
name String
|
|
slug String @unique
|
|
description String?
|
|
sortOrder Int @default(0)
|
|
parentId Int?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
parent Category? @relation("CategoryTree", fields: [parentId], references: [id])
|
|
children Category[] @relation("CategoryTree")
|
|
contents Content[]
|
|
courses Course[]
|
|
prompts Prompt[]
|
|
tools Tool[]
|
|
|
|
@@index([parentId], map: "categories_parentId_fkey")
|
|
@@map("categories")
|
|
}
|
|
|
|
model Course {
|
|
id Int @id @default(autoincrement())
|
|
title String
|
|
description String?
|
|
cover String?
|
|
categoryId Int?
|
|
price Float @default(0)
|
|
isFree Boolean @default(true)
|
|
status ContentStatus @default(DRAFT)
|
|
sortOrder Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
deletedAt DateTime?
|
|
chapters Chapter[]
|
|
assignments CourseAssignment[]
|
|
category Category? @relation(fields: [categoryId], references: [id])
|
|
progress LearnRecord[]
|
|
|
|
@@index([categoryId], map: "courses_categoryId_fkey")
|
|
@@map("courses")
|
|
}
|
|
|
|
model Chapter {
|
|
id Int @id @default(autoincrement())
|
|
courseId Int
|
|
title String
|
|
sortOrder Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
|
|
lessons Lesson[]
|
|
|
|
@@index([courseId], map: "chapters_courseId_fkey")
|
|
@@map("chapters")
|
|
}
|
|
|
|
model Lesson {
|
|
id Int @id @default(autoincrement())
|
|
chapterId Int
|
|
title String
|
|
content String? @db.Text
|
|
videoUrl String?
|
|
duration Int?
|
|
sortOrder Int @default(0)
|
|
status ContentStatus @default(DRAFT)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
progress LearnRecord[]
|
|
chapter Chapter @relation(fields: [chapterId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([chapterId], map: "lessons_chapterId_fkey")
|
|
@@map("lessons")
|
|
}
|
|
|
|
model LearnRecord {
|
|
id Int @id @default(autoincrement())
|
|
userId Int
|
|
courseId Int
|
|
lessonId Int
|
|
completed Boolean @default(false)
|
|
progress Float @default(0)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
|
|
lesson Lesson @relation(fields: [lessonId], references: [id], onDelete: Cascade)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([userId, lessonId])
|
|
@@index([courseId], map: "learn_records_courseId_fkey")
|
|
@@index([lessonId], map: "learn_records_lessonId_fkey")
|
|
@@map("learn_records")
|
|
}
|
|
|
|
model Prompt {
|
|
id Int @id @default(autoincrement())
|
|
title String
|
|
content String @db.Text
|
|
description String?
|
|
categoryId Int?
|
|
tags String?
|
|
authorId Int?
|
|
model String?
|
|
isPublic Boolean @default(true)
|
|
status ContentStatus @default(PUBLISHED)
|
|
viewCount Int @default(0)
|
|
likeCount Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
deletedAt DateTime?
|
|
favorites PromptFavorite[]
|
|
author User? @relation(fields: [authorId], references: [id])
|
|
category Category? @relation(fields: [categoryId], references: [id])
|
|
|
|
@@index([authorId], map: "prompts_authorId_fkey")
|
|
@@index([categoryId], map: "prompts_categoryId_fkey")
|
|
@@map("prompts")
|
|
}
|
|
|
|
model PromptFavorite {
|
|
id Int @id @default(autoincrement())
|
|
userId Int
|
|
promptId Int
|
|
createdAt DateTime @default(now())
|
|
prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([userId, promptId])
|
|
@@index([promptId], map: "prompt_favorites_promptId_fkey")
|
|
@@map("prompt_favorites")
|
|
}
|
|
|
|
model Tool {
|
|
id Int @id @default(autoincrement())
|
|
slug String? @unique(map: "slug") @db.VarChar(200)
|
|
name String
|
|
metaTitle String? @db.VarChar(200)
|
|
metaDesc String? @db.VarChar(300)
|
|
description String?
|
|
content String? @db.LongText
|
|
url String
|
|
icon String?
|
|
categoryId Int?
|
|
tags String?
|
|
isFeatured Boolean @default(false)
|
|
status ContentStatus @default(PUBLISHED)
|
|
viewCount Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
deletedAt DateTime?
|
|
affiliateLink String?
|
|
category Category? @relation(fields: [categoryId], references: [id])
|
|
|
|
@@index([categoryId], map: "tools_categoryId_fkey")
|
|
@@map("tools")
|
|
}
|
|
|
|
model Content {
|
|
id Int @id @default(autoincrement())
|
|
title String
|
|
summary String?
|
|
content String? @db.Text
|
|
cover String?
|
|
categoryId Int?
|
|
tags String?
|
|
authorName String?
|
|
contentType String @default("article")
|
|
status ContentStatus @default(DRAFT)
|
|
viewCount Int @default(0)
|
|
isAiGenerated Boolean @default(false)
|
|
publishedAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
deletedAt DateTime?
|
|
category Category? @relation(fields: [categoryId], references: [id])
|
|
|
|
@@index([categoryId], map: "contents_categoryId_fkey")
|
|
@@map("contents")
|
|
}
|
|
|
|
model AiModel {
|
|
id Int @id @default(autoincrement())
|
|
name String
|
|
provider String
|
|
description String?
|
|
capabilities String?
|
|
contextWindow Int?
|
|
maxTokens Int?
|
|
pricing String?
|
|
isFree Boolean @default(false)
|
|
isFeatured Boolean @default(false)
|
|
icon String?
|
|
sortOrder Int @default(0)
|
|
status String @default("ACTIVE")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@map("ai_models")
|
|
}
|
|
|
|
model Skill {
|
|
id String @id
|
|
name String
|
|
description String
|
|
icon String
|
|
category String
|
|
difficulty String
|
|
systemPrompt String @db.Text
|
|
starters String @db.Text
|
|
tasks String @db.Text
|
|
tags String
|
|
prerequisiteIds String?
|
|
sortOrder Int @default(0)
|
|
status String @default("ACTIVE")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
price Float? @default(0)
|
|
purchasedBy UserSkill[]
|
|
|
|
@@map("skills")
|
|
}
|
|
|
|
model SandboxSession {
|
|
id Int @id @default(autoincrement())
|
|
userId Int
|
|
conversationId String @default("")
|
|
model String
|
|
title String @default("AI 对话")
|
|
messages String @db.Text
|
|
feedback String?
|
|
tokens Int @default(0)
|
|
duration Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([userId, conversationId])
|
|
@@index([userId, createdAt])
|
|
@@map("sandbox_sessions")
|
|
}
|
|
|
|
model Order {
|
|
id Int @id @default(autoincrement())
|
|
orderNo String @unique
|
|
userId Int
|
|
amount Float
|
|
planType String
|
|
status OrderStatus @default(PENDING)
|
|
payChannel String?
|
|
paidAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
transactionId String?
|
|
gatewayOrderId String?
|
|
metadata String?
|
|
user User @relation(fields: [userId], references: [id])
|
|
userSkills UserSkill[]
|
|
|
|
@@index([userId, status])
|
|
@@index([status, createdAt])
|
|
@@map("orders")
|
|
}
|
|
|
|
model UserSkill {
|
|
id Int @id @default(autoincrement())
|
|
userId Int
|
|
skillId String
|
|
orderId Int?
|
|
purchasedAt DateTime @default(now())
|
|
order Order? @relation(fields: [orderId], references: [id])
|
|
skill Skill @relation(fields: [skillId], references: [id])
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([userId, skillId])
|
|
@@index([orderId], map: "user_skills_orderId_fkey")
|
|
@@index([skillId], map: "user_skills_skillId_fkey")
|
|
@@map("user_skills")
|
|
}
|
|
|
|
model Subscription {
|
|
id Int @id @default(autoincrement())
|
|
userId Int
|
|
plan MemberPlan
|
|
startDate DateTime
|
|
endDate DateTime
|
|
status String @default("ACTIVE")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
user User @relation(fields: [userId], references: [id])
|
|
|
|
@@index([userId, status])
|
|
@@map("subscriptions")
|
|
}
|
|
|
|
model AdminRole {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
description String?
|
|
permissions Json
|
|
status String @default("ACTIVE")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
admins AdminUser[]
|
|
|
|
@@map("admin_roles")
|
|
}
|
|
|
|
model AdminUser {
|
|
id Int @id @default(autoincrement())
|
|
username String @unique
|
|
passwordHash String
|
|
nickname String?
|
|
roleId String?
|
|
status String @default("ACTIVE")
|
|
lastLoginAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
role AdminRole? @relation(fields: [roleId], references: [id])
|
|
|
|
@@index([roleId], map: "admin_users_roleId_fkey")
|
|
@@map("admin_users")
|
|
}
|
|
|
|
model AdminLog {
|
|
id Int @id @default(autoincrement())
|
|
adminId Int
|
|
action String
|
|
target String?
|
|
detail String?
|
|
ip String?
|
|
createdAt DateTime @default(now())
|
|
|
|
@@map("admin_logs")
|
|
}
|
|
|
|
model Post {
|
|
id Int @id @default(autoincrement())
|
|
userId Int
|
|
title String
|
|
content String @db.Text
|
|
tags String?
|
|
circleId Int?
|
|
status String @default("PUBLISHED")
|
|
viewCount Int @default(0)
|
|
likeCount Int @default(0)
|
|
commentCount Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
comments Comment[]
|
|
likes PostLike[]
|
|
circle Circle? @relation(fields: [circleId], references: [id])
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([userId])
|
|
@@index([status, createdAt])
|
|
@@index([circleId])
|
|
@@map("posts")
|
|
}
|
|
|
|
model Comment {
|
|
id Int @id @default(autoincrement())
|
|
postId Int
|
|
userId Int
|
|
content String
|
|
parentId Int?
|
|
status String @default("PUBLISHED")
|
|
reviewNote String?
|
|
reviewedAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
parent Comment? @relation("CommentReply", fields: [parentId], references: [id])
|
|
replies Comment[] @relation("CommentReply")
|
|
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([postId])
|
|
@@index([status])
|
|
@@index([parentId], map: "comments_parentId_fkey")
|
|
@@index([userId], map: "comments_userId_fkey")
|
|
@@map("comments")
|
|
}
|
|
|
|
model PostLike {
|
|
id Int @id @default(autoincrement())
|
|
postId Int
|
|
userId Int
|
|
createdAt DateTime @default(now())
|
|
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([postId, userId])
|
|
@@index([userId], map: "post_likes_userId_fkey")
|
|
@@map("post_likes")
|
|
}
|
|
|
|
model Circle {
|
|
id Int @id @default(autoincrement())
|
|
name String
|
|
description String?
|
|
tags String?
|
|
creatorId Int
|
|
isPublic Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
members CircleMember[]
|
|
creator User @relation("CircleCreator", fields: [creatorId], references: [id])
|
|
posts Post[]
|
|
|
|
@@index([creatorId], map: "circles_creatorId_fkey")
|
|
@@map("circles")
|
|
}
|
|
|
|
model CircleMember {
|
|
id Int @id @default(autoincrement())
|
|
circleId Int
|
|
userId Int
|
|
role String @default("member")
|
|
joinedAt DateTime @default(now())
|
|
circle Circle @relation(fields: [circleId], references: [id], onDelete: Cascade)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([circleId, userId])
|
|
@@index([userId], map: "circle_members_userId_fkey")
|
|
@@map("circle_members")
|
|
}
|
|
|
|
model Follow {
|
|
id Int @id @default(autoincrement())
|
|
followerId Int
|
|
followingId Int
|
|
createdAt DateTime @default(now())
|
|
follower User @relation("Follower", fields: [followerId], references: [id], onDelete: Cascade)
|
|
following User @relation("Following", fields: [followingId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([followerId, followingId])
|
|
@@index([followingId], map: "follows_followingId_fkey")
|
|
@@map("follows")
|
|
}
|
|
|
|
model Organization {
|
|
id Int @id @default(autoincrement())
|
|
name String
|
|
description String?
|
|
contactName String?
|
|
contactPhone String?
|
|
logo String?
|
|
memberCount Int @default(0)
|
|
status String @default("ACTIVE")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
assignments CourseAssignment[]
|
|
members OrganizationMember[]
|
|
|
|
@@map("organizations")
|
|
}
|
|
|
|
model OrganizationMember {
|
|
id Int @id @default(autoincrement())
|
|
organizationId Int
|
|
userId Int
|
|
role String @default("MEMBER")
|
|
status String @default("ACTIVE")
|
|
joinedAt DateTime @default(now())
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([organizationId, userId])
|
|
@@index([userId], map: "organization_members_userId_fkey")
|
|
@@map("organization_members")
|
|
}
|
|
|
|
model CourseAssignment {
|
|
id Int @id @default(autoincrement())
|
|
organizationId Int
|
|
courseId Int
|
|
assignedBy Int
|
|
deadline DateTime?
|
|
createdAt DateTime @default(now())
|
|
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([courseId], map: "course_assignments_courseId_fkey")
|
|
@@index([organizationId], map: "course_assignments_organizationId_fkey")
|
|
@@map("course_assignments")
|
|
}
|
|
|
|
model Notification {
|
|
id Int @id @default(autoincrement())
|
|
userId Int
|
|
type String
|
|
title String
|
|
content String?
|
|
link String?
|
|
relatedId Int?
|
|
isRead Boolean @default(false)
|
|
createdAt DateTime @default(now())
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([userId, isRead])
|
|
@@map("notifications")
|
|
}
|
|
|
|
model PracticeQuestion {
|
|
id Int @id @default(autoincrement())
|
|
skillId String?
|
|
scenario String @db.Text
|
|
title String
|
|
description String @db.Text
|
|
instructions String @db.Text
|
|
difficulty String @default("BEGINNER")
|
|
category String @default("general")
|
|
expectedCriteria String @db.Text
|
|
starterCode String? @db.Text
|
|
hint String? @db.Text
|
|
sortOrder Int @default(0)
|
|
status String @default("PUBLISHED")
|
|
attemptCount Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
submissions PracticeSubmission[]
|
|
|
|
@@map("practice_questions")
|
|
}
|
|
|
|
model PracticeSubmission {
|
|
id Int @id @default(autoincrement())
|
|
userId Int
|
|
questionId Int
|
|
answer String @db.Text
|
|
score Int?
|
|
maxScore Int @default(100)
|
|
feedback String? @db.Text
|
|
criteriaScores String? @db.Text
|
|
duration Int @default(0)
|
|
status String @default("SUBMITTED")
|
|
submittedAt DateTime @default(now())
|
|
scoredAt DateTime?
|
|
question PracticeQuestion @relation(fields: [questionId], references: [id], onDelete: Cascade)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([userId])
|
|
@@index([questionId])
|
|
@@index([userId, status])
|
|
@@map("practice_submissions")
|
|
}
|
|
|
|
model Banner {
|
|
id Int @id @default(autoincrement())
|
|
title String
|
|
image String
|
|
link String?
|
|
position String @default("home")
|
|
sortOrder Int @default(0)
|
|
status String @default("DRAFT")
|
|
startAt DateTime?
|
|
endAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@map("banners")
|
|
}
|
|
|
|
model SystemNotification {
|
|
id Int @id @default(autoincrement())
|
|
title String
|
|
content String
|
|
type String @default("system")
|
|
target String @default("all")
|
|
targetIds String?
|
|
status String @default("DRAFT")
|
|
scheduledAt DateTime?
|
|
sentAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@map("system_notifications")
|
|
}
|
|
|
|
model SystemConfig {
|
|
id String @id @default(cuid())
|
|
category String
|
|
key String @unique
|
|
value String
|
|
description String?
|
|
status String @default("ACTIVE")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@map("system_configs")
|
|
}
|
|
|
|
enum UserStatus {
|
|
ACTIVE
|
|
INACTIVE
|
|
BANNED
|
|
}
|
|
|
|
enum ContentStatus {
|
|
DRAFT
|
|
PUBLISHED
|
|
ARCHIVED
|
|
}
|
|
|
|
enum OrderStatus {
|
|
PENDING
|
|
PAID
|
|
CANCELLED
|
|
REFUNDED
|
|
}
|
|
|
|
enum MemberPlan {
|
|
FREE
|
|
MONTHLY
|
|
YEARLY
|
|
}
|
|
|
|
model AffiliateProgram {
|
|
id Int @id @default(autoincrement())
|
|
name String
|
|
slug String @unique
|
|
provider String?
|
|
description String?
|
|
commissionRate String?
|
|
cookieDays Int?
|
|
homepageUrl String?
|
|
logo String?
|
|
active Boolean @default(true)
|
|
sortOrder Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
links AffiliateLink[]
|
|
|
|
@@map("affiliate_programs")
|
|
}
|
|
|
|
model AffiliateLink {
|
|
id Int @id @default(autoincrement())
|
|
programId Int
|
|
title String
|
|
description String?
|
|
url String
|
|
thumbnail String?
|
|
toolId Int?
|
|
skillId String?
|
|
tags String?
|
|
estimatedCommission Float @default(0)
|
|
sortOrder Int @default(0)
|
|
isFeatured Boolean @default(false)
|
|
active Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
clicks AffiliateClick[]
|
|
program AffiliateProgram @relation(fields: [programId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([programId])
|
|
@@index([toolId])
|
|
@@index([skillId])
|
|
@@map("affiliate_links")
|
|
}
|
|
|
|
model AffiliateClick {
|
|
id Int @id @default(autoincrement())
|
|
linkId Int
|
|
userId Int?
|
|
ip String?
|
|
userAgent String?
|
|
ref String?
|
|
createdAt DateTime @default(now())
|
|
link AffiliateLink @relation(fields: [linkId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([linkId])
|
|
@@map("affiliate_clicks")
|
|
}
|
|
|
|
model Donation {
|
|
id Int @id @default(autoincrement())
|
|
name String?
|
|
message String? @db.VarChar(280)
|
|
channel String @default("ALIPAY")
|
|
amount Float?
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([createdAt])
|
|
@@map("donations")
|
|
}
|