Files
ftb-project-management/apps/server/prisma/schema.prisma
2026-07-08 17:02:51 +08:00

468 lines
16 KiB
Plaintext

generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(cuid())
email String @unique
name String
avatar String?
username String? @unique
departmentId String? @map("department_id")
roleId String @default("member") @map("role_id")
phone String @default("")
password String @default("")
isSystem Boolean @default(false) @map("is_system")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
createdTasks Task[] @relation("TaskCreator")
assignedTasks Task[] @relation("TaskAssignee")
projectMembers ProjectMember[]
requirements Requirement[]
watchedTasks TaskWatcher[]
@@map("users")
}
model Product {
id String @id @default(cuid())
name String
description String @default("")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
projects Project[]
requirements Requirement[]
versions Version[]
@@map("products")
}
model Project {
id String @id @default(cuid())
productId String @map("product_id")
name String
description String @default("")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
product Product @relation(fields: [productId], references: [id])
sprints Sprint[]
tasks Task[]
versions Version[]
members ProjectMember[]
@@map("projects")
}
model Sprint {
id String @id @default(cuid())
projectId String @map("project_id")
name String
startDate DateTime @map("start_date")
endDate DateTime @map("end_date")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
project Project @relation(fields: [projectId], references: [id])
tasks Task[]
@@map("sprints")
}
model Version {
id String @id @default(cuid())
productId String @map("product_id")
projectId String? @map("project_id")
name String
description String @default("")
status String @default("planned")
currentStage String? @map("current_stage")
startDate DateTime? @map("start_date")
expectedReleaseDate DateTime? @map("expected_release_date")
releaseDate DateTime? @map("release_date")
members Json @default("[]")
progress Json @default("[]")
priority Int?
links Json @default("{}")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
product Product @relation(fields: [productId], references: [id])
project Project? @relation(fields: [projectId], references: [id])
tasks Task[]
@@map("versions")
}
model Requirement {
id String @default(cuid())
productId String @map("product_id")
projectId String? @map("project_id")
versionId String? @map("version_id")
code String
title String
description String @default("")
status String @default("pending_review")
priority Int @default(0)
type String?
sourceType String? @map("source_type")
sourceTarget String? @map("source_target")
platform String?
creatorId String? @map("creator_id")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
product Product @relation(fields: [productId], references: [id])
creator User? @relation(fields: [creatorId], references: [id])
@@id([id, productId])
@@unique([productId, code])
@@map("requirements")
}
model Task {
id String @id @default(cuid())
projectId String @map("project_id")
sprintId String? @map("sprint_id")
versionId String? @map("version_id")
parentId String? @map("parent_id")
title String
description String @default("")
status String @default("todo")
priority Int @default(0)
assigneeId String? @map("assignee_id")
creatorId String @map("creator_id")
startDate DateTime? @map("start_date")
dueDate DateTime? @map("due_date")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
project Project @relation(fields: [projectId], references: [id])
sprint Sprint? @relation(fields: [sprintId], references: [id])
version Version? @relation(fields: [versionId], references: [id])
parent Task? @relation("TaskChildren", fields: [parentId], references: [id])
children Task[] @relation("TaskChildren")
assignee User? @relation("TaskAssignee", fields: [assigneeId], references: [id])
creator User @relation("TaskCreator", fields: [creatorId], references: [id])
watchers TaskWatcher[]
comments Comment[]
@@map("tasks")
}
model TaskWatcher {
id String @id @default(cuid())
taskId String @map("task_id")
userId String @map("user_id")
task Task @relation(fields: [taskId], references: [id])
user User @relation(fields: [userId], references: [id])
@@unique([taskId, userId])
@@map("task_watchers")
}
model Comment {
id String @id @default(cuid())
taskId String @map("task_id")
authorId String @map("author_id")
content String
createdAt DateTime @default(now()) @map("created_at")
task Task @relation(fields: [taskId], references: [id])
@@map("comments")
}
model ProjectMember {
id String @id @default(cuid())
projectId String @map("project_id")
userId String @map("user_id")
role String @default("member")
project Project @relation(fields: [projectId], references: [id])
user User @relation(fields: [userId], references: [id])
@@unique([projectId, userId])
@@map("project_members")
}
model TaskCategory {
id String @id @default(cuid())
name String
code String?
group String
isSystem Boolean @default(false) @map("is_system")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@unique([group, name])
@@map("task_categories")
}
model VersionPlan {
id String @id @default(cuid())
versionId String @map("version_id")
productId String @map("product_id")
projectId String? @map("project_id")
type String
title String
status String @default("pending")
ownerId String? @map("owner_id")
expectedStartAt DateTime? @map("expected_start_at")
expectedEndAt DateTime? @map("expected_end_at")
actualStartAt DateTime? @map("actual_start_at")
completedAt DateTime? @map("completed_at")
resultUrl String? @map("result_url")
requirementCoverage Json @default("[]") @map("requirement_coverage")
logs Json @default("[]")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("version_plans")
}
model DevTask {
id String @default(cuid())
versionId String @map("version_id")
productId String @map("product_id")
projectId String @map("project_id")
requirementId String? @map("requirement_id")
requirementProductId String? @map("requirement_product_id")
categoryId String? @map("category_id")
code String
title String
description String @default("")
status String @default("todo")
priority Int @default(0)
assigneeId String? @map("assignee_id")
creatorId String? @map("creator_id")
isBlocked Boolean @default(false) @map("is_blocked")
blockReason String? @map("block_reason")
expectedStartAt DateTime? @map("expected_start_at")
expectedEndAt DateTime? @map("expected_end_at")
startDate DateTime? @map("start_date")
completedAt DateTime? @map("completed_at")
estimateHours Float? @map("estimate_hours")
aiEstimateHours Float? @map("ai_estimate_hours")
references Json @default("[]")
aiDraft Boolean @default(false) @map("ai_draft")
aiDraftAt DateTime? @map("ai_draft_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@id([id, versionId])
@@unique([versionId, code])
@@map("dev_tasks")
}
model TestCase {
id String @default(cuid())
versionId String @map("version_id")
productId String @map("product_id")
projectId String @map("project_id")
requirementId String? @map("requirement_id")
requirementProductId String? @map("requirement_product_id")
categoryId String? @map("category_id")
code String
title String
description String @default("")
status String @default("pending")
roundNo Int @default(1) @map("round_no")
priority Int @default(0)
assigneeId String? @map("assignee_id")
creatorId String? @map("creator_id")
plannedTestAt DateTime? @map("planned_test_at")
plannedEndAt DateTime? @map("planned_end_at")
startedAt DateTime? @map("started_at")
completedAt DateTime? @map("completed_at")
estimateHours Float? @map("estimate_hours")
aiEstimateHours Float? @map("ai_estimate_hours")
references Json @default("[]")
aiDraft Boolean @default(false) @map("ai_draft")
aiDraftAt DateTime? @map("ai_draft_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@id([id, versionId])
@@unique([versionId, code])
@@map("test_cases")
}
model Bug {
id String @default(cuid())
versionId String @map("version_id")
productId String @map("product_id")
projectId String @map("project_id")
testCaseId String? @map("test_case_id")
testCaseVersionId String? @map("test_case_version_id")
code String
title String
description String @default("")
status String @default("open")
severity String @default("normal")
priority Int @default(0)
assigneeId String? @map("assignee_id")
reporterId String? @map("reporter_id")
plannedFixAt DateTime? @map("planned_fix_at")
resolvedAt DateTime? @map("resolved_at")
closedAt DateTime? @map("closed_at")
resolution String?
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@id([id, versionId])
@@unique([versionId, code])
@@map("bugs")
}
model WorkActivity {
id String @default(cuid())
versionId String? @map("version_id")
productId String? @map("product_id")
projectId String? @map("project_id")
actorId String? @map("actor_id")
actorName String @default("") @map("actor_name")
sourceType String @map("source_type")
sourceId String @map("source_id")
sourceVersionId String? @map("source_version_id")
action String
title String
metadata Json @default("{}")
occurredAt DateTime @map("occurred_at")
createdAt DateTime @default(now()) @map("created_at")
@@id([id, createdAt])
@@map("work_activities")
}
model TaskWorklog {
id String @default(cuid())
versionId String? @map("version_id")
productId String? @map("product_id")
projectId String? @map("project_id")
userId String? @map("user_id")
sourceType String @map("source_type")
sourceId String @map("source_id")
sourceVersionId String? @map("source_version_id")
workDate DateTime @db.Date @map("work_date")
hours Float @default(0)
content String @default("")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@id([id, createdAt])
@@map("task_worklogs")
}
model OvertimeRecord {
id String @default(cuid())
productId String? @map("product_id")
projectId String? @map("project_id")
versionId String? @map("version_id")
userId String? @map("user_id")
reason String @default("")
startAt DateTime @map("start_at")
endAt DateTime @map("end_at")
hours Float @default(0)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@id([id, createdAt])
@@map("overtime_records")
}
model XiaobaoRiskSnapshot {
id String @default(cuid())
versionId String @map("version_id")
snapshotDate DateTime @db.Date @map("snapshot_date")
riskLevel String @map("risk_level")
riskScore Int @default(0) @map("risk_score")
riskSignature String @map("risk_signature")
snapshot Json
createdAt DateTime @default(now()) @map("created_at")
@@id([id, createdAt])
@@map("xiaobao_risk_snapshots")
}
model XiaobaoRiskInsight {
id String @default(cuid())
versionId String @map("version_id")
riskSignature String @map("risk_signature")
status String @default("generated")
insight Json
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@id([id, createdAt])
@@map("xiaobao_risk_insights")
}
model AiLog {
id String @default(cuid())
provider String
model String
operation String
status String
promptTokens Int @default(0) @map("prompt_tokens")
completionTokens Int @default(0) @map("completion_tokens")
durationMs Int @default(0) @map("duration_ms")
errorMessage String? @map("error_message")
metadata Json @default("{}")
createdAt DateTime @default(now()) @map("created_at")
@@id([id, createdAt])
@@map("ai_logs")
}
model BackgroundJob {
id String @id @default(cuid())
type String
status String @default("queued")
dedupeKey String? @map("dedupe_key")
payload Json @default("{}")
attempts Int @default(0)
maxAttempts Int @default(3) @map("max_attempts")
availableAt DateTime @default(now()) @map("available_at")
lockedBy String? @map("locked_by")
lockedUntil DateTime? @map("locked_until")
lastError String? @map("last_error")
completedAt DateTime? @map("completed_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("background_jobs")
}
model XiaobaoRiskSummary {
versionId String @id @map("version_id")
riskLevel String @map("risk_level")
riskScore Int @default(0) @map("risk_score")
confidence Int @default(0)
forecastReleaseDate DateTime? @map("forecast_release_date")
riskSignature String @map("risk_signature")
summary Json
dirty Boolean @default(false)
recomputedAt DateTime? @map("recomputed_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("xiaobao_risk_summaries")
}
model AppData {
key String @id
value Json
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("app_data")
}