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[]

  @@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())
  entityType         String    @map("entity_type")
  entityId           String    @map("entity_id")
  entityVersionId    String?   @map("entity_version_id")
  productId          String?   @map("product_id")
  projectId          String?   @map("project_id")
  versionId          String?   @map("version_id")
  authorId           String    @map("author_id")
  content            String
  mentionedMemberIds Json      @default("[]") @map("mentioned_member_ids")
  deletedAt          DateTime? @map("deleted_at")
  createdAt          DateTime  @default(now()) @map("created_at")
  updatedAt          DateTime  @updatedAt @map("updated_at")

  @@index([entityType, entityId, createdAt], name: "comments_entity_created_idx")
  @@index([authorId, createdAt], name: "comments_author_created_idx")
  @@map("comments")
}

model ProjectMember {
  id        String   @id @default(cuid())
  projectId String   @map("project_id")
  userId    String   @map("user_id")
  role      String   @default("member")
  createdAt DateTime @default(now()) @map("created_at")
  updatedAt DateTime @updatedAt @map("updated_at")

  project Project @relation(fields: [projectId], references: [id])
  user    User    @relation(fields: [userId], references: [id])

  @@unique([projectId, userId])
  @@index([userId, role], name: "project_members_user_role_idx")
  @@map("project_members")
}

model Notification {
  id                String    @id @default(cuid())
  recipientId       String    @map("recipient_id")
  actorId           String?   @map("actor_id")
  type              String
  title             String
  body              String    @default("")
  resourceType      String    @map("resource_type")
  resourceId        String    @map("resource_id")
  resourceVersionId String?   @map("resource_version_id")
  productId         String?   @map("product_id")
  projectId         String?   @map("project_id")
  versionId         String?   @map("version_id")
  metadata          Json      @default("{}")
  readAt            DateTime? @map("read_at")
  createdAt         DateTime  @default(now()) @map("created_at")

  @@index([recipientId, readAt, createdAt], name: "notifications_recipient_read_created_idx")
  @@index([resourceType, resourceId], name: "notifications_resource_idx")
  @@map("notifications")
}

model AuditLog {
  id           String   @id @default(cuid())
  actorId      String?  @map("actor_id")
  action       String
  resourceType String   @map("resource_type")
  resourceId   String   @map("resource_id")
  productId    String?  @map("product_id")
  projectId    String?  @map("project_id")
  versionId    String?  @map("version_id")
  before       Json     @default("{}")
  after        Json     @default("{}")
  metadata     Json     @default("{}")
  createdAt    DateTime @default(now()) @map("created_at")

  @@index([resourceType, resourceId, createdAt], name: "audit_logs_resource_created_idx")
  @@index([actorId, createdAt], name: "audit_logs_actor_created_idx")
  @@map("audit_logs")
}

model GovernanceDictionary {
  id        String    @id @default(cuid())
  scope     String    @default("global")
  kind      String
  name      String
  code      String?
  group     String?
  value     Json      @default("{}")
  isSystem  Boolean   @default(false) @map("is_system")
  deletedAt DateTime? @map("deleted_at")
  createdAt DateTime  @default(now()) @map("created_at")
  updatedAt DateTime  @updatedAt @map("updated_at")

  @@unique([scope, kind, name])
  @@index([kind, deletedAt], name: "governance_dictionaries_kind_deleted_idx")
  @@map("governance_dictionaries")
}

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 AuditEvent {
  id         String   @default(cuid())
  actorId    String?  @map("actor_id")
  actorName  String   @default("") @map("actor_name")
  action     String
  entityType String   @map("entity_type")
  entityId   String   @map("entity_id")
  productId  String?  @map("product_id")
  projectId  String?  @map("project_id")
  versionId  String?  @map("version_id")
  scope      Json     @default("{}")
  before     Json?
  after      Json?
  metadata   Json     @default("{}")
  createdAt  DateTime @default(now()) @map("created_at")

  @@id([id, createdAt])
  @@map("audit_events")
}

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")
}
