From 76c45c71325452659122121985f95cad20f4eea4 Mon Sep 17 00:00:00 2001 From: mzaxd Date: Tue, 27 Jan 2026 21:32:57 +0800 Subject: [PATCH] feat: add AIEvent model to database schema --- prisma/schema.prisma | 373 +++++++++++++++++++------------------------ 1 file changed, 166 insertions(+), 207 deletions(-) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 7b9fa2d..38e6549 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -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") }