feat: add AIEvent model to database schema

This commit is contained in:
2026-01-27 21:32:57 +08:00
parent e1f250d397
commit 76c45c7132
+166 -207
View File
@@ -1,6 +1,3 @@
// 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"
previewFeatures = ["postgresqlExtensions"]
@@ -11,13 +8,153 @@ datasource db {
url = env("DATABASE_URL")
}
// ================================
// Enums
// ================================
model external_links {
id String @id
type LinkType
url String
title String?
projectId String
projects projects @relation(fields: [projectId], references: [id], onDelete: Cascade)
enum ProjectStatus {
ACTIVE
ARCHIVED
@@unique([projectId, url])
@@index([projectId], map: "idx_link_projectId")
@@index([type], map: "idx_link_type")
@@index([type, url], map: "idx_link_type_url")
@@index([url], map: "idx_link_url")
}
model keyword_cloud_error_logs {
id Int @id @default(autoincrement())
quarter String
keyword String?
errorType String
errorMessage String
rawData Json?
createdAt DateTime @default(now())
@@index([errorType], map: "idx_keywordCloudErrorLog_errorType")
@@index([quarter], map: "idx_keywordCloudErrorLog_quarter")
}
model keywords {
id Int @id @default(autoincrement())
word String
trendScore Int
quarterId Int
description String
descriptionEn String?
detailPoints Json
detailPointsEn Json?
visualConfig Json
createdAt DateTime @default(now())
updatedAt DateTime
quarters quarters @relation(fields: [quarterId], references: [id], onDelete: Cascade)
@@index([quarterId], map: "idx_keyword_quarterId")
@@index([trendScore], map: "idx_keyword_trendScore")
@@index([word], map: "idx_keyword_word")
}
model project_discovery_tasks {
id String @id
status TaskStatus @default(PENDING)
sourceUrl String
sourceType String @default("manual")
explorationData Json?
explorationSummary String?
errorMessage String?
retryCount Int @default(0)
lastRetryAt DateTime?
projectId String?
createdAt DateTime @default(now())
startedAt DateTime?
completedAt DateTime?
updatedAt DateTime
projects projects? @relation(fields: [projectId], references: [id])
@@index([projectId], map: "idx_task_project_id")
@@index([sourceUrl], map: "idx_task_source_url")
@@index([status, createdAt], map: "idx_task_status_created")
}
model project_tags {
projectId String
tagId String
projects projects @relation(fields: [projectId], references: [id], onDelete: Cascade)
tags tags @relation(fields: [tagId], references: [id], onDelete: Cascade)
@@id([projectId, tagId])
@@index([tagId])
}
model projects {
id String @id
name String
nameEn String?
slug String @unique
description String
descriptionEn String?
content String?
contentEn String?
status ProjectStatus @default(ACTIVE)
source String?
createdAt DateTime @default(now())
updatedAt DateTime
embedding Unsupported("vector")?
embeddingUpdatedAt DateTime?
external_links external_links[]
project_discovery_tasks project_discovery_tasks[]
project_tags project_tags[]
@@index([embedding], map: "idx_project_embedding_cosine")
@@index([slug], map: "idx_project_slug")
@@index([status, createdAt], map: "idx_project_status_createdAt")
}
model quarters {
id Int @id @default(autoincrement())
quarter String @unique
title String
titleEn String?
subtitle String?
subtitleEn String?
displayOrder Int @default(0)
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime
keywords keywords[]
@@index([displayOrder], map: "idx_quarter_displayOrder")
@@index([quarter], map: "idx_quarter_quarter")
}
model tags {
id String @id
name String @unique
nameEn String?
slug String @unique
createdAt DateTime @default(now())
project_tags project_tags[]
@@index([slug], map: "idx_tag_slug")
}
model visual_style_rules {
id Int @id @default(autoincrement())
name String @unique
minScore Int
maxScore Int
color String
size String
border String
rotation String?
priority Int @default(0)
enabled Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime
@@index([enabled], map: "idx_visualStyleRule_enabled")
@@index([minScore, maxScore], map: "idx_visualStyleRule_scoreRange")
}
enum LinkType {
@@ -27,6 +164,11 @@ enum LinkType {
PAPER
}
enum ProjectStatus {
ACTIVE
ARCHIVED
}
enum TaskStatus {
PENDING
IN_PROGRESS
@@ -35,206 +177,23 @@ enum TaskStatus {
}
// ================================
// Models
// AI Timeline System Models
// ================================
model Project {
id String @id @default(cuid())
name String
nameEn String?
slug String @unique
description String
descriptionEn String?
content String? @db.Text
contentEn String? @db.Text
status ProjectStatus @default(ACTIVE)
source String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
model AIEvent {
id String @id @default(cuid())
title String
titleEn String?
eventDate DateTime
description String
descriptionEn String?
imageUrl String
sourceUrl String?
// Relations
tags ProjectTag[]
links ExternalLink[]
discoveryTasks ProjectDiscoveryTask[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Indexes
@@index([status, createdAt], map: "idx_project_status_createdAt")
@@index([slug], map: "idx_project_slug")
@@map("projects")
}
model Tag {
id String @id @default(cuid())
name String @unique
nameEn String?
slug String @unique
createdAt DateTime @default(now())
// Relations
projects ProjectTag[]
// Indexes
@@index([slug], map: "idx_tag_slug")
@@map("tags")
}
model ExternalLink {
id String @id @default(cuid())
type LinkType
url String
title String?
projectId String
// Relations
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
// Indexes
@@index([projectId], map: "idx_link_projectId")
@@index([type], map: "idx_link_type")
@@index([url], map: "idx_link_url")
@@index([type, url], map: "idx_link_type_url")
@@unique([projectId, url])
@@map("external_links")
}
// Project-Tag many-to-many relationship table
model ProjectTag {
projectId String
tagId String
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
tag Tag @relation(fields: [tagId], references: [id], onDelete: Cascade)
@@id([projectId, tagId])
@@index([tagId])
@@map("project_tags")
}
// Project Discovery Task model
model ProjectDiscoveryTask {
id String @id @default(cuid())
status TaskStatus @default(PENDING)
// 原始数据(仅URL
sourceUrl String
sourceType String @default("manual")
// 探索结果
explorationData Json?
explorationSummary String? @db.Text
// 错误处理
errorMessage String? @db.Text
retryCount Int @default(0)
lastRetryAt DateTime?
// 关联
projectId String?
project Project? @relation(fields: [projectId], references: [id])
// 时间戳
createdAt DateTime @default(now())
startedAt DateTime?
completedAt DateTime?
updatedAt DateTime @updatedAt
// 索引
@@index([status, createdAt], map: "idx_task_status_created")
@@index([sourceUrl], map: "idx_task_source_url")
@@index([projectId], map: "idx_task_project_id")
@@map("project_discovery_tasks")
}
// ================================
// Keyword Cloud System Models
// ================================
// 季度元数据表
model Quarter {
id Int @id @default(autoincrement())
quarter String @unique // "2023-Q1", "2023-Q2"
title String @db.Text // "2023年第一季度"
titleEn String? @db.Text // "Q1 2023"
subtitle String? @db.Text // "聊天界面的黎明"
subtitleEn String? @db.Text // "The dawn of chat interface"
displayOrder Int @default(0) // 前端排序
isActive Boolean @default(true) // 是否显示
keywords Keyword[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([quarter], map: "idx_quarter_quarter")
@@index([displayOrder], map: "idx_quarter_displayOrder")
@@map("quarters")
}
// 关键词核心数据表
model Keyword {
id Int @id @default(autoincrement())
word String // "ChatGPT"
trendScore Int // 0-100, 从 Google Trends 获取
// 外键关联
quarterId Int
quarter Quarter @relation(fields: [quarterId], references: [id], onDelete: Cascade)
// 内容字段(支持中英双语)
description String @db.Text // AI 生成的一句话描述
descriptionEn String? @db.Text // 英文描述
detailPoints Json // JSON 数组: ["要点1", "要点2", "要点3"]
detailPointsEn Json? // 英文版要点
// 视觉样式配置
visualConfig Json // {color, size, rotation, border}
// 元数据
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([quarterId], map: "idx_keyword_quarterId")
@@index([trendScore], map: "idx_keyword_trendScore")
@@index([word], map: "idx_keyword_word")
@@map("keywords")
}
// 视觉样式规则配置表
model VisualStyleRule {
id Int @id @default(autoincrement())
name String @unique // "热门大词-金色"
// 分数区间
minScore Int // 90
maxScore Int // 100
// 视觉属性
color String // "primary", "secondary", "accent"
size String // "text-5xl", "text-3xl", "text-xl"
border String // "border-4", "border-2"
rotation String? // "rotate-1", "rotate-2", null
// 控制
priority Int @default(0) // 优先级,分数重叠时按优先级
enabled Boolean @default(true) // 是否启用
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([enabled], map: "idx_visualStyleRule_enabled")
@@index([minScore, maxScore], map: "idx_visualStyleRule_scoreRange")
@@map("visual_style_rules")
}
// 错误日志表
model KeywordCloudErrorLog {
id Int @id @default(autoincrement())
quarter String // "2023-Q1"
keyword String? // "ChatGPT"
errorType String // "INVALID_DATA", "API_ERROR", "DB_ERROR"
errorMessage String @db.Text // 详细错误信息
rawData Json? // 原始数据便于调试
createdAt DateTime @default(now())
@@index([quarter], map: "idx_keywordCloudErrorLog_quarter")
@@index([errorType], map: "idx_keywordCloudErrorLog_errorType")
@@map("keyword_cloud_error_logs")
@@index([eventDate(sort: Desc)])
@@index([createdAt])
@@map("ai_events")
}