新增功能: - 新增 ProjectDiscoveryTask 数据模型,支持异步项目探索任务管理 - 新增 /api/discovery/tasks CRUD API,支持任务创建、查询和状态更新 - 新增 /api/discovery/tasks/:id/complete API,完成探索并自动创建项目 - 新增 discovery-service 服务层,封装多级去重和标签处理逻辑 - 新增 discover-projects 命令,支持批量探索项目 - 新增 PROJECT_CONTENT_STANDARD.md 内容标准模板 代码质量修复: - 修复状态转换验证未使用问题,防止非法状态转换 - 修复 explorationData 类型安全问题,使用 z.record(z.unknown()) 替代 z.any() - 添加事务保护到 complete API,确保项目创建和任务状态更新的原子性 代码重构: - 将 webhook/projects 的去重逻辑迁移到 discovery-service - 统一探索任务相关的验证模式到 validations.ts Co-Authored-By: Claude <noreply@anthropic.com>
147 lines
3.4 KiB
Plaintext
147 lines
3.4 KiB
Plaintext
// 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"]
|
||
}
|
||
|
||
datasource db {
|
||
provider = "postgresql"
|
||
url = env("DATABASE_URL")
|
||
}
|
||
|
||
// ================================
|
||
// Enums
|
||
// ================================
|
||
|
||
enum ProjectStatus {
|
||
ACTIVE
|
||
ARCHIVED
|
||
}
|
||
|
||
enum LinkType {
|
||
WEBSITE
|
||
GITHUB
|
||
HUGGINGFACE
|
||
PAPER
|
||
}
|
||
|
||
enum TaskStatus {
|
||
PENDING
|
||
IN_PROGRESS
|
||
COMPLETED
|
||
FAILED
|
||
}
|
||
|
||
// ================================
|
||
// 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
|
||
|
||
// Relations
|
||
tags ProjectTag[]
|
||
links ExternalLink[]
|
||
discoveryTasks ProjectDiscoveryTask[]
|
||
|
||
// 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")
|
||
}
|