generator client { provider = "prisma-client-js" previewFeatures = ["postgresqlExtensions"] } datasource db { provider = "postgresql" url = env("DATABASE_URL") } model ExternalLink { id String @id @default(cuid()) type LinkType url String title String? projectId String project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) @@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") @@map("external_links") } model KeywordCloudErrorLog { 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") @@map("keyword_cloud_error_logs") } model Keyword { 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 @updatedAt quarter Quarter @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") @@map("keywords") } model ProjectDiscoveryTask { id String @id @default(cuid()) 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 @updatedAt project Project? @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") @@map("project_discovery_tasks") } 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") } model Project { id String @id @default(cuid()) 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 @updatedAt embedding Unsupported("vector")? embeddingUpdatedAt DateTime? links ExternalLink[] projectDiscoveryTasks ProjectDiscoveryTask[] tags ProjectTag[] @@index([embedding], map: "idx_project_embedding_cosine") @@index([slug], map: "idx_project_slug") @@index([status, createdAt], map: "idx_project_status_createdAt") @@map("projects") } model Quarter { 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 @updatedAt keywords Keyword[] @@index([displayOrder], map: "idx_quarter_displayOrder") @@index([quarter], map: "idx_quarter_quarter") @@map("quarters") } model Tag { id String @id @default(cuid()) name String @unique nameEn String? slug String @unique createdAt DateTime @default(now()) projects ProjectTag[] @@index([slug], map: "idx_tag_slug") @@map("tags") } model VisualStyleRule { 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 @updatedAt @@index([enabled], map: "idx_visualStyleRule_enabled") @@index([minScore, maxScore], map: "idx_visualStyleRule_scoreRange") @@map("visual_style_rules") } enum LinkType { WEBSITE GITHUB HUGGINGFACE PAPER } enum ProjectStatus { ACTIVE ARCHIVED } enum TaskStatus { PENDING IN_PROGRESS COMPLETED FAILED } // ================================ // AI Timeline System Models // ================================ model AIEvent { id String @id @default(cuid()) title String titleEn String? eventDate DateTime description String descriptionEn String? imageUrl String sourceUrl String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([eventDate(sort: Desc)]) @@index([createdAt]) @@map("ai_events") }