Replace FeedbackSeverity enum (Critical/Major/Minor/Suggestion) with a simple isActionItem boolean. Annotations default to action items (things the artist must fix). Any item can be toggled to an info callout (context that doesn't need action). Progress bar and carry-forward only count action items. Screenshot paste limited to 5MB with user notification. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
806 lines
24 KiB
Text
806 lines
24 KiB
Text
generator client {
|
|
provider = "prisma-client"
|
|
output = "../src/generated/prisma"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
}
|
|
|
|
// ─── Enums ──────────────────────────────────────────────
|
|
|
|
enum Role {
|
|
ADMIN
|
|
PRODUCER
|
|
ARTIST
|
|
}
|
|
|
|
enum ProjectStatus {
|
|
ACTIVE
|
|
ON_HOLD
|
|
COMPLETED
|
|
ARCHIVED
|
|
}
|
|
|
|
enum Priority {
|
|
LOW
|
|
MEDIUM
|
|
HIGH
|
|
URGENT
|
|
}
|
|
|
|
enum DeliverableStatus {
|
|
NOT_STARTED
|
|
IN_PROGRESS
|
|
IN_REVIEW
|
|
APPROVED
|
|
ON_HOLD
|
|
}
|
|
|
|
enum StageStatus {
|
|
BLOCKED
|
|
NOT_STARTED
|
|
IN_PROGRESS
|
|
IN_REVIEW
|
|
CHANGES_REQUESTED
|
|
APPROVED
|
|
DELIVERED
|
|
SKIPPED
|
|
}
|
|
|
|
enum RevisionStatus {
|
|
SUBMITTED
|
|
IN_REVIEW
|
|
CHANGES_REQUESTED
|
|
APPROVED
|
|
}
|
|
|
|
enum NotificationType {
|
|
ASSIGNMENT
|
|
STATUS_CHANGE
|
|
REVISION_SUBMITTED
|
|
REVISION_FEEDBACK
|
|
COMMENT
|
|
DEADLINE_APPROACHING
|
|
DEADLINE_OVERDUE
|
|
STAGE_UNBLOCKED
|
|
}
|
|
|
|
enum AssignmentRole {
|
|
LEAD
|
|
SUPPORT
|
|
}
|
|
|
|
enum SkillLevel {
|
|
JUNIOR
|
|
INTERMEDIATE
|
|
SENIOR
|
|
LEAD
|
|
}
|
|
|
|
// ─── RBAC ──────────────────────────────────────────────
|
|
|
|
model OrgRolePermission {
|
|
id String @id @default(cuid())
|
|
organizationId String
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
role Role
|
|
permission Permission
|
|
|
|
@@unique([organizationId, role, permission])
|
|
@@index([organizationId])
|
|
@@map("org_role_permissions")
|
|
}
|
|
|
|
// ─── Organization ───────────────────────────────────────
|
|
|
|
model Organization {
|
|
id String @id @default(cuid())
|
|
name String
|
|
domain String @unique
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
users User[]
|
|
projects Project[]
|
|
automationRules AutomationRule[]
|
|
rolePermissions OrgRolePermission[]
|
|
pipelineTemplates PipelineTemplate[]
|
|
deliverables Deliverable[]
|
|
deliverableStages DeliverableStage[]
|
|
invitations Invitation[]
|
|
customFieldDefs CustomFieldDefinition[]
|
|
notificationRules NotificationRule[]
|
|
|
|
@@map("organizations")
|
|
}
|
|
|
|
// ─── Auth.js models ─────────────────────────────────────
|
|
|
|
model User {
|
|
id String @id @default(cuid())
|
|
name String?
|
|
email String @unique
|
|
emailVerified DateTime?
|
|
image String?
|
|
role Role @default(ARTIST)
|
|
department String?
|
|
maxCapacity Int @default(5)
|
|
|
|
organizationId String?
|
|
organization Organization? @relation(fields: [organizationId], references: [id])
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
accounts Account[]
|
|
sessions Session[]
|
|
assignments StageAssignment[]
|
|
comments Comment[]
|
|
notifications Notification[]
|
|
skills UserSkill[]
|
|
searchLogs SearchLog[]
|
|
automationRules AutomationRule[] @relation("AutomationCreator")
|
|
chatMessages ChatMessage[]
|
|
invitationsSent Invitation[] @relation("InvitedBy")
|
|
annotations Annotation[]
|
|
feedbackCreated FeedbackItem[] @relation("FeedbackCreator")
|
|
feedbackAssigned FeedbackItem[] @relation("FeedbackAssignee")
|
|
feedbackResolved FeedbackItem[] @relation("FeedbackResolver")
|
|
feedbackVerified FeedbackItem[] @relation("FeedbackVerifier")
|
|
colorProbes ColorProbe[]
|
|
|
|
@@map("users")
|
|
}
|
|
|
|
model Account {
|
|
id String @id @default(cuid())
|
|
userId String
|
|
type String
|
|
provider String
|
|
providerAccountId String
|
|
refresh_token String? @db.Text
|
|
access_token String? @db.Text
|
|
expires_at Int?
|
|
token_type String?
|
|
scope String?
|
|
id_token String? @db.Text
|
|
session_state String?
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([provider, providerAccountId])
|
|
@@map("accounts")
|
|
}
|
|
|
|
model Session {
|
|
id String @id @default(cuid())
|
|
sessionToken String @unique
|
|
userId String
|
|
expires DateTime
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("sessions")
|
|
}
|
|
|
|
model VerificationToken {
|
|
identifier String
|
|
token String
|
|
expires DateTime
|
|
|
|
@@unique([identifier, token])
|
|
@@map("verification_tokens")
|
|
}
|
|
|
|
// ─── Pipeline Templates (seed data) ────────────────────
|
|
|
|
model PipelineStageTemplate {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
slug String @unique
|
|
order Int @unique
|
|
isCriticalGate Boolean @default(false)
|
|
isOptional Boolean @default(false)
|
|
description String?
|
|
estimatedDays Float?
|
|
|
|
dependsOn PipelineStageDependency[] @relation("DependsOnStage")
|
|
dependedBy PipelineStageDependency[] @relation("PrerequisiteStage")
|
|
|
|
deliverableStages DeliverableStage[]
|
|
skillRequirements StageSkillRequirement[]
|
|
|
|
@@map("pipeline_stage_templates")
|
|
}
|
|
|
|
model PipelineStageDependency {
|
|
id String @id @default(cuid())
|
|
stageId String
|
|
prerequisiteId String
|
|
|
|
stage PipelineStageTemplate @relation("DependsOnStage", fields: [stageId], references: [id])
|
|
prerequisite PipelineStageTemplate @relation("PrerequisiteStage", fields: [prerequisiteId], references: [id])
|
|
|
|
@@unique([stageId, prerequisiteId])
|
|
@@map("pipeline_stage_dependencies")
|
|
}
|
|
|
|
// ─── Dynamic Pipeline Templates (org-scoped) ───────────
|
|
|
|
model PipelineTemplate {
|
|
id String @id @default(cuid())
|
|
name String
|
|
description String?
|
|
organizationId String
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
isArchived Boolean @default(false)
|
|
isDefault Boolean @default(false)
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
stages PipelineStageDefinition[]
|
|
projects Project[]
|
|
|
|
@@unique([organizationId, name])
|
|
@@index([organizationId])
|
|
@@map("pipeline_templates")
|
|
}
|
|
|
|
model PipelineStageDefinition {
|
|
id String @id @default(cuid())
|
|
pipelineId String
|
|
pipeline PipelineTemplate @relation(fields: [pipelineId], references: [id], onDelete: Cascade)
|
|
name String
|
|
slug String
|
|
order Int
|
|
isCriticalGate Boolean @default(false)
|
|
isOptional Boolean @default(false)
|
|
description String?
|
|
estimatedDays Float?
|
|
color String?
|
|
customStatuses Json?
|
|
|
|
dependsOn PipelineStageDependencyV2[] @relation("DependsOnStageV2")
|
|
dependedBy PipelineStageDependencyV2[] @relation("PrerequisiteStageV2")
|
|
|
|
deliverableStages DeliverableStage[]
|
|
|
|
@@unique([pipelineId, slug])
|
|
@@unique([pipelineId, order])
|
|
@@map("pipeline_stage_definitions")
|
|
}
|
|
|
|
model PipelineStageDependencyV2 {
|
|
id String @id @default(cuid())
|
|
stageId String
|
|
prerequisiteId String
|
|
|
|
stage PipelineStageDefinition @relation("DependsOnStageV2", fields: [stageId], references: [id], onDelete: Cascade)
|
|
prerequisite PipelineStageDefinition @relation("PrerequisiteStageV2", fields: [prerequisiteId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([stageId, prerequisiteId])
|
|
@@map("pipeline_stage_dependencies_v2")
|
|
}
|
|
|
|
// ─── Project ────────────────────────────────────────────
|
|
|
|
model Project {
|
|
id String @id @default(cuid())
|
|
projectCode String @unique
|
|
name String
|
|
description String?
|
|
status ProjectStatus @default(ACTIVE)
|
|
priority Priority @default(MEDIUM)
|
|
startDate DateTime?
|
|
dueDate DateTime?
|
|
businessUnit String?
|
|
formFactor String?
|
|
codeName String?
|
|
npiOrRefresh String?
|
|
quarter String?
|
|
requestor String?
|
|
workfrontId String?
|
|
omgCode String?
|
|
bmtId String?
|
|
estimatedCost Float?
|
|
actualCost Float?
|
|
agency String?
|
|
|
|
// pgvector embedding for semantic search (raw SQL — Prisma can't query this directly)
|
|
embedding Unsupported("vector(768)")?
|
|
customFields Json?
|
|
|
|
organizationId String
|
|
organization Organization @relation(fields: [organizationId], references: [id])
|
|
|
|
pipelineTemplateId String?
|
|
pipelineTemplate PipelineTemplate? @relation(fields: [pipelineTemplateId], references: [id])
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
deliverables Deliverable[]
|
|
|
|
@@index([organizationId])
|
|
@@index([pipelineTemplateId])
|
|
@@index([status])
|
|
@@map("projects")
|
|
}
|
|
|
|
// ─── Deliverable ────────────────────────────────────────
|
|
|
|
model Deliverable {
|
|
id String @id @default(cuid())
|
|
name String
|
|
status DeliverableStatus @default(NOT_STARTED)
|
|
priority Priority @default(MEDIUM)
|
|
dueDate DateTime?
|
|
notes String?
|
|
cmfSku String?
|
|
assetCount Int?
|
|
requestedDueDate DateTime?
|
|
plannedDeliveryDate DateTime?
|
|
actualDeliveryDate DateTime?
|
|
wfInputDate DateTime?
|
|
|
|
// pgvector embedding for semantic search (raw SQL — Prisma can't query this directly)
|
|
embedding Unsupported("vector(768)")?
|
|
customFields Json?
|
|
|
|
projectId String
|
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
|
organizationId String?
|
|
organization Organization? @relation(fields: [organizationId], references: [id])
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
stages DeliverableStage[]
|
|
|
|
@@index([projectId])
|
|
@@index([organizationId])
|
|
@@index([status])
|
|
@@map("deliverables")
|
|
}
|
|
|
|
// ─── Deliverable Stage (instance per deliverable) ───────
|
|
|
|
model DeliverableStage {
|
|
id String @id @default(cuid())
|
|
status StageStatus @default(BLOCKED)
|
|
revisionRound Int @default(0)
|
|
startDate DateTime?
|
|
completedDate DateTime?
|
|
dueDate DateTime?
|
|
notes String?
|
|
subStatus String?
|
|
manualSchedule Boolean @default(false)
|
|
scheduleConflict Boolean @default(false)
|
|
scheduleDelta Int?
|
|
|
|
deliverableId String
|
|
deliverable Deliverable @relation(fields: [deliverableId], references: [id], onDelete: Cascade)
|
|
|
|
templateId String
|
|
template PipelineStageTemplate @relation(fields: [templateId], references: [id])
|
|
|
|
stageDefinitionId String?
|
|
stageDefinition PipelineStageDefinition? @relation(fields: [stageDefinitionId], references: [id])
|
|
|
|
organizationId String?
|
|
organization Organization? @relation(fields: [organizationId], references: [id])
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
assignments StageAssignment[]
|
|
revisions Revision[]
|
|
comments Comment[]
|
|
feedbackItems FeedbackItem[]
|
|
|
|
@@unique([deliverableId, templateId])
|
|
@@index([deliverableId])
|
|
@@index([stageDefinitionId])
|
|
@@index([organizationId])
|
|
@@index([status])
|
|
@@map("deliverable_stages")
|
|
}
|
|
|
|
// ─── Stage Assignment ───────────────────────────────────
|
|
|
|
model StageAssignment {
|
|
id String @id @default(cuid())
|
|
role AssignmentRole? @default(LEAD)
|
|
|
|
deliverableStageId String
|
|
deliverableStage DeliverableStage @relation(fields: [deliverableStageId], references: [id], onDelete: Cascade)
|
|
|
|
userId String
|
|
user User @relation(fields: [userId], references: [id])
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@unique([deliverableStageId, userId])
|
|
@@index([userId])
|
|
@@map("stage_assignments")
|
|
}
|
|
|
|
// ─── Revision ───────────────────────────────────────────
|
|
|
|
model Revision {
|
|
id String @id @default(cuid())
|
|
roundNumber Int
|
|
status RevisionStatus @default(SUBMITTED)
|
|
feedbackNotes String?
|
|
internalNotes String?
|
|
attachments Json?
|
|
|
|
deliverableStageId String
|
|
deliverableStage DeliverableStage @relation(fields: [deliverableStageId], references: [id], onDelete: Cascade)
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
annotations Annotation[]
|
|
feedbackItems FeedbackItem[]
|
|
colorProbes ColorProbe[]
|
|
|
|
@@index([deliverableStageId])
|
|
@@map("revisions")
|
|
}
|
|
|
|
// ─── Comment ────────────────────────────────────────────
|
|
|
|
model Comment {
|
|
id String @id @default(cuid())
|
|
content String @db.Text
|
|
|
|
deliverableStageId String
|
|
deliverableStage DeliverableStage @relation(fields: [deliverableStageId], references: [id], onDelete: Cascade)
|
|
|
|
authorId String
|
|
author User @relation(fields: [authorId], references: [id])
|
|
|
|
parentId String?
|
|
parent Comment? @relation("CommentThread", fields: [parentId], references: [id])
|
|
replies Comment[] @relation("CommentThread")
|
|
|
|
annotations Annotation[]
|
|
feedbackItems FeedbackItem[]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([deliverableStageId])
|
|
@@index([parentId])
|
|
@@map("comments")
|
|
}
|
|
|
|
// ─── Notification ───────────────────────────────────────
|
|
|
|
model Notification {
|
|
id String @id @default(cuid())
|
|
type NotificationType
|
|
title String
|
|
message String
|
|
link String?
|
|
isRead Boolean @default(false)
|
|
|
|
userId String
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([userId, isRead])
|
|
@@map("notifications")
|
|
}
|
|
|
|
// ─── Skills & Capacity (Phase 6) ────────────────────────
|
|
|
|
model Skill {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
createdAt DateTime @default(now())
|
|
|
|
users UserSkill[]
|
|
stageRequirements StageSkillRequirement[]
|
|
|
|
@@map("skills")
|
|
}
|
|
|
|
model UserSkill {
|
|
userId String
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
skillId String
|
|
skill Skill @relation(fields: [skillId], references: [id], onDelete: Cascade)
|
|
level SkillLevel @default(INTERMEDIATE)
|
|
|
|
@@id([userId, skillId])
|
|
@@map("user_skills")
|
|
}
|
|
|
|
model StageSkillRequirement {
|
|
stageTemplateId String
|
|
stageTemplate PipelineStageTemplate @relation(fields: [stageTemplateId], references: [id], onDelete: Cascade)
|
|
skillId String
|
|
skill Skill @relation(fields: [skillId], references: [id], onDelete: Cascade)
|
|
importance Int @default(1) // 1=nice-to-have, 2=important, 3=required
|
|
|
|
@@id([stageTemplateId, skillId])
|
|
@@map("stage_skill_requirements")
|
|
}
|
|
|
|
// ─── Automation Engine (Phase 7.1) ──────────────────────
|
|
|
|
model AutomationRule {
|
|
id String @id @default(cuid())
|
|
name String
|
|
description String?
|
|
organizationId String
|
|
organization Organization @relation(fields: [organizationId], references: [id])
|
|
isEnabled Boolean @default(true)
|
|
trigger Json // { event, conditions[] }
|
|
actions Json // [{ type, params }]
|
|
createdById String
|
|
createdBy User @relation("AutomationCreator", fields: [createdById], references: [id])
|
|
executions AutomationExecution[]
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([organizationId])
|
|
@@index([isEnabled])
|
|
@@map("automation_rules")
|
|
}
|
|
|
|
model AutomationExecution {
|
|
id String @id @default(cuid())
|
|
ruleId String
|
|
rule AutomationRule @relation(fields: [ruleId], references: [id], onDelete: Cascade)
|
|
triggeredBy Json // the event payload that triggered execution
|
|
result Json // what actions were taken + outcomes
|
|
status ExecutionStatus
|
|
error String?
|
|
executedAt DateTime @default(now())
|
|
|
|
@@index([ruleId])
|
|
@@index([executedAt])
|
|
@@map("automation_executions")
|
|
}
|
|
|
|
enum ExecutionStatus {
|
|
SUCCESS
|
|
PARTIAL_FAILURE
|
|
FAILURE
|
|
}
|
|
|
|
enum Permission {
|
|
PROJECT_CREATE
|
|
PROJECT_UPDATE
|
|
PROJECT_DELETE
|
|
PROJECT_VIEW
|
|
DELIVERABLE_CREATE
|
|
DELIVERABLE_UPDATE
|
|
DELIVERABLE_DELETE
|
|
STAGE_UPDATE_STATUS
|
|
STAGE_ASSIGN
|
|
STAGE_SCHEDULE
|
|
REVISION_CREATE
|
|
REVISION_REVIEW
|
|
COMMENT_CREATE
|
|
COMMENT_DELETE_ANY
|
|
PIPELINE_MANAGE
|
|
USER_MANAGE
|
|
ROLE_MANAGE
|
|
ORG_SETTINGS
|
|
AUTOMATION_MANAGE
|
|
FIELD_CUSTOMIZE
|
|
}
|
|
|
|
// ─── Chat History (CLI Anything) ────────────────────────
|
|
|
|
model ChatMessage {
|
|
id String @id @default(cuid())
|
|
sessionId String
|
|
role String // "user" | "assistant" | "system"
|
|
content String @db.Text
|
|
toolCalls Json? // tool calls made by assistant
|
|
toolResults Json? // results of tool execution
|
|
metadata Json? // context: active project, etc.
|
|
userId String
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
organizationId String
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([sessionId])
|
|
@@index([userId])
|
|
@@map("chat_messages")
|
|
}
|
|
|
|
// ─── Custom Fields ──────────────────────────────────────
|
|
|
|
model CustomFieldDefinition {
|
|
id String @id @default(cuid())
|
|
organizationId String
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
entityType String // "PROJECT" | "DELIVERABLE"
|
|
fieldName String
|
|
fieldType String // "TEXT" | "NUMBER" | "DATE" | "SELECT" | "BOOLEAN"
|
|
fieldOptions Json? // For SELECT type: { options: string[] }
|
|
isRequired Boolean @default(false)
|
|
order Int @default(0)
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@unique([organizationId, entityType, fieldName])
|
|
@@index([organizationId])
|
|
@@map("custom_field_definitions")
|
|
}
|
|
|
|
// ─── Notification Rules ─────────────────────────────────
|
|
|
|
model NotificationRule {
|
|
id String @id @default(cuid())
|
|
organizationId String
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
name String
|
|
isEnabled Boolean @default(true)
|
|
event String // e.g. "STAGE_STATUS_CHANGE", "DEADLINE_APPROACHING", "REVISION_SUBMITTED"
|
|
conditions Json? // { field: string, operator: string, value: any }[]
|
|
channels Json // ["IN_APP", "EMAIL"]
|
|
recipientRoles Json // ["ADMIN", "PRODUCER"] or ["ASSIGNEE"]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([organizationId])
|
|
@@index([event])
|
|
@@map("notification_rules")
|
|
}
|
|
|
|
// ─── Invitations ────────────────────────────────────────
|
|
|
|
model Invitation {
|
|
id String @id @default(cuid())
|
|
email String
|
|
role Role @default(ARTIST)
|
|
organizationId String
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
invitedById String
|
|
invitedBy User @relation("InvitedBy", fields: [invitedById], references: [id])
|
|
token String @unique @default(cuid())
|
|
expiresAt DateTime
|
|
acceptedAt DateTime?
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@unique([email, organizationId])
|
|
@@index([organizationId])
|
|
@@index([token])
|
|
@@map("invitations")
|
|
}
|
|
|
|
// ─── Semantic Search (Phase 8.4) ────────────────────────
|
|
|
|
model SearchLog {
|
|
id String @id @default(cuid())
|
|
userId String
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
query String
|
|
resultCount Int @default(0)
|
|
clickedId String?
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([userId])
|
|
@@map("search_logs")
|
|
}
|
|
|
|
// ─── Annotations (Visual Review) ────────────────────────
|
|
|
|
enum AnnotationType {
|
|
RECTANGLE
|
|
ELLIPSE
|
|
ARROW
|
|
FREEHAND
|
|
TEXT
|
|
PIN
|
|
SCREENSHOT
|
|
}
|
|
|
|
enum FeedbackStatus {
|
|
OPEN
|
|
IN_PROGRESS
|
|
RESOLVED
|
|
VERIFIED
|
|
REOPENED
|
|
}
|
|
|
|
// ─── Annotation ─────────────────────────────────────────
|
|
|
|
model Annotation {
|
|
id String @id @default(cuid())
|
|
commentId String
|
|
comment Comment @relation(fields: [commentId], references: [id], onDelete: Cascade)
|
|
revisionId String
|
|
revision Revision @relation(fields: [revisionId], references: [id], onDelete: Cascade)
|
|
type AnnotationType
|
|
data Json
|
|
imageX Float
|
|
imageY Float
|
|
createdById String
|
|
createdBy User @relation(fields: [createdById], references: [id])
|
|
createdAt DateTime @default(now())
|
|
|
|
feedbackItems FeedbackItem[]
|
|
|
|
@@index([commentId])
|
|
@@index([revisionId])
|
|
@@map("annotations")
|
|
}
|
|
|
|
// ─── Color Probe ────────────────────────────────────────
|
|
|
|
model ColorProbe {
|
|
id String @id @default(cuid())
|
|
revisionId String
|
|
revision Revision @relation(fields: [revisionId], references: [id], onDelete: Cascade)
|
|
index Int
|
|
workingX Float
|
|
workingY Float
|
|
referenceX Float
|
|
referenceY Float
|
|
createdById String
|
|
createdBy User @relation(fields: [createdById], references: [id])
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@unique([revisionId, index])
|
|
@@index([revisionId])
|
|
@@map("color_probes")
|
|
}
|
|
|
|
// ─── Feedback Item ──────────────────────────────────────
|
|
|
|
model FeedbackItem {
|
|
id String @id @default(cuid())
|
|
deliverableStageId String
|
|
deliverableStage DeliverableStage @relation(fields: [deliverableStageId], references: [id], onDelete: Cascade)
|
|
revisionId String
|
|
revision Revision @relation(fields: [revisionId], references: [id], onDelete: Cascade)
|
|
annotationId String?
|
|
annotation Annotation? @relation(fields: [annotationId], references: [id], onDelete: SetNull)
|
|
commentId String?
|
|
comment Comment? @relation(fields: [commentId], references: [id], onDelete: SetNull)
|
|
summary String
|
|
isActionItem Boolean @default(true) // true = action item (must fix), false = info callout
|
|
status FeedbackStatus @default(OPEN)
|
|
sortOrder Int @default(0)
|
|
assignedToId String?
|
|
assignedTo User? @relation("FeedbackAssignee", fields: [assignedToId], references: [id], onDelete: SetNull)
|
|
createdById String
|
|
createdBy User @relation("FeedbackCreator", fields: [createdById], references: [id])
|
|
resolvedById String?
|
|
resolvedBy User? @relation("FeedbackResolver", fields: [resolvedById], references: [id], onDelete: SetNull)
|
|
resolvedAt DateTime?
|
|
resolutionNote String?
|
|
verifiedById String?
|
|
verifiedBy User? @relation("FeedbackVerifier", fields: [verifiedById], references: [id], onDelete: SetNull)
|
|
verifiedAt DateTime?
|
|
carriedFromId String?
|
|
carriedFrom FeedbackItem? @relation("FeedbackCarry", fields: [carriedFromId], references: [id], onDelete: SetNull)
|
|
carriedTo FeedbackItem[] @relation("FeedbackCarry")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([deliverableStageId])
|
|
@@index([revisionId])
|
|
@@index([assignedToId])
|
|
@@index([status])
|
|
@@map("feedback_items")
|
|
}
|
|
|
|
// FeedbackSeverity removed — replaced by isActionItem boolean
|
|
// Action items = things the artist must fix (default for annotations)
|
|
// Info callouts = context/reference that doesn't need action
|