Fix build errors: add missing Prisma models/fields and resolve TypeScript type errors
Schema: Add 11 new models (RoundTemplate, MentorNote, MentorMilestone, MentorMilestoneCompletion, EvaluationDiscussion, DiscussionComment, Message, MessageRecipient, MessageTemplate, Webhook, WebhookDelivery, DigestLog) and missing fields on existing models (Project.isDraft, ProjectFile.version, LiveVotingSession.allowAudienceVotes, User.digestFrequency, AuditLog.sessionId, MentorAssignment.completionStatus, etc). Add AUDIT_CONFIG/LOCALIZATION/DIGEST/ANALYTICS enum values. Code: Fix implicit any types, route type casts, enum casts, null safety, composite key handling, and relation field names across 11 source files. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -110,6 +110,10 @@ enum SettingCategory {
|
||||
SECURITY
|
||||
DEFAULTS
|
||||
WHATSAPP
|
||||
AUDIT_CONFIG
|
||||
LOCALIZATION
|
||||
DIGEST
|
||||
ANALYTICS
|
||||
}
|
||||
|
||||
enum NotificationChannel {
|
||||
@@ -222,6 +226,11 @@ model User {
|
||||
inviteToken String? @unique
|
||||
inviteTokenExpiresAt DateTime?
|
||||
|
||||
// Digest & availability preferences
|
||||
digestFrequency String? // 'none' | 'daily' | 'weekly'
|
||||
preferredWorkload Int?
|
||||
availabilityJson Json? @db.JsonB // { startDate?: string, endDate?: string }
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
lastLoginAt DateTime?
|
||||
@@ -272,6 +281,30 @@ model User {
|
||||
// Wizard templates
|
||||
wizardTemplates WizardTemplate[] @relation("WizardTemplateCreatedBy")
|
||||
|
||||
// Round templates
|
||||
roundTemplates RoundTemplate[] @relation("RoundTemplateCreatedBy")
|
||||
|
||||
// Mentor notes
|
||||
mentorNotes MentorNote[] @relation("MentorNoteAuthor")
|
||||
|
||||
// Milestone completions
|
||||
milestoneCompletions MentorMilestoneCompletion[] @relation("MilestoneCompletedBy")
|
||||
|
||||
// Evaluation discussions
|
||||
closedDiscussions EvaluationDiscussion[] @relation("DiscussionClosedBy")
|
||||
discussionComments DiscussionComment[] @relation("DiscussionCommentAuthor")
|
||||
|
||||
// Messaging
|
||||
sentMessages Message[] @relation("MessageSender")
|
||||
receivedMessages MessageRecipient[] @relation("MessageRecipient")
|
||||
messageTemplates MessageTemplate[] @relation("MessageTemplateCreator")
|
||||
|
||||
// Webhooks
|
||||
webhooks Webhook[] @relation("WebhookCreator")
|
||||
|
||||
// Digest logs
|
||||
digestLogs DigestLog[] @relation("DigestLog")
|
||||
|
||||
// NextAuth relations
|
||||
accounts Account[]
|
||||
sessions Session[]
|
||||
@@ -344,6 +377,8 @@ model Program {
|
||||
specialAwards SpecialAward[]
|
||||
taggingJobs TaggingJob[]
|
||||
wizardTemplates WizardTemplate[]
|
||||
roundTemplates RoundTemplate[]
|
||||
mentorMilestones MentorMilestone[]
|
||||
|
||||
@@unique([name, year])
|
||||
@@index([status])
|
||||
@@ -415,6 +450,8 @@ model Round {
|
||||
taggingJobs TaggingJob[]
|
||||
reminderLogs ReminderLog[]
|
||||
projectFiles ProjectFile[]
|
||||
evaluationDiscussions EvaluationDiscussion[]
|
||||
messages Message[]
|
||||
|
||||
@@index([programId])
|
||||
@@index([status])
|
||||
@@ -499,6 +536,11 @@ model Project {
|
||||
logoKey String? // Storage key (e.g., "logos/project456/1234567890.png")
|
||||
logoProvider String? // Storage provider used: 's3' or 'local'
|
||||
|
||||
// Draft support
|
||||
isDraft Boolean @default(false)
|
||||
draftDataJson Json? @db.JsonB // Form data for drafts
|
||||
draftExpiresAt DateTime?
|
||||
|
||||
// Flexible fields
|
||||
tags String[] @default([]) // "Ocean Conservation", "Tech", etc.
|
||||
metadataJson Json? @db.JsonB // Custom fields from Typeform, etc.
|
||||
@@ -523,6 +565,7 @@ model Project {
|
||||
statusHistory ProjectStatusHistory[]
|
||||
mentorMessages MentorMessage[]
|
||||
evaluationSummaries EvaluationSummary[]
|
||||
evaluationDiscussions EvaluationDiscussion[]
|
||||
|
||||
@@index([programId])
|
||||
@@index([roundId])
|
||||
@@ -553,11 +596,17 @@ model ProjectFile {
|
||||
|
||||
isLate Boolean @default(false) // Uploaded after round deadline
|
||||
|
||||
// Versioning
|
||||
version Int @default(1)
|
||||
replacedById String? // FK to the newer file that replaced this one
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
// Relations
|
||||
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
||||
round Round? @relation(fields: [roundId], references: [id])
|
||||
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
||||
round Round? @relation(fields: [roundId], references: [id])
|
||||
replacedBy ProjectFile? @relation("FileVersions", fields: [replacedById], references: [id], onDelete: SetNull)
|
||||
replacements ProjectFile[] @relation("FileVersions")
|
||||
|
||||
@@unique([bucket, objectKey])
|
||||
@@index([projectId])
|
||||
@@ -705,6 +754,7 @@ model AuditLog {
|
||||
// Request info
|
||||
ipAddress String?
|
||||
userAgent String?
|
||||
sessionId String?
|
||||
|
||||
timestamp DateTime @default(now())
|
||||
|
||||
@@ -716,6 +766,7 @@ model AuditLog {
|
||||
@@index([entityType, entityId])
|
||||
@@index([timestamp])
|
||||
@@index([entityType, entityId, timestamp])
|
||||
@@index([sessionId])
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@@ -969,32 +1020,39 @@ model ProjectTag {
|
||||
// =============================================================================
|
||||
|
||||
model LiveVotingSession {
|
||||
id String @id @default(cuid())
|
||||
roundId String @unique
|
||||
status String @default("NOT_STARTED") // NOT_STARTED, IN_PROGRESS, PAUSED, COMPLETED
|
||||
currentProjectIndex Int @default(0)
|
||||
currentProjectId String?
|
||||
votingStartedAt DateTime?
|
||||
votingEndsAt DateTime?
|
||||
projectOrderJson Json? @db.JsonB // Array of project IDs in presentation order
|
||||
id String @id @default(cuid())
|
||||
roundId String @unique
|
||||
status String @default("NOT_STARTED") // NOT_STARTED, IN_PROGRESS, PAUSED, COMPLETED
|
||||
currentProjectIndex Int @default(0)
|
||||
currentProjectId String?
|
||||
votingStartedAt DateTime?
|
||||
votingEndsAt DateTime?
|
||||
projectOrderJson Json? @db.JsonB // Array of project IDs in presentation order
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
// Audience & presentation settings
|
||||
allowAudienceVotes Boolean @default(false)
|
||||
audienceVoteWeight Float? // 0.0 to 1.0
|
||||
tieBreakerMethod String? // 'admin_decides' | 'highest_individual' | 'revote'
|
||||
presentationSettingsJson Json? @db.JsonB
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// Relations
|
||||
round Round @relation(fields: [roundId], references: [id], onDelete: Cascade)
|
||||
votes LiveVote[]
|
||||
round Round @relation(fields: [roundId], references: [id], onDelete: Cascade)
|
||||
votes LiveVote[]
|
||||
|
||||
@@index([status])
|
||||
}
|
||||
|
||||
model LiveVote {
|
||||
id String @id @default(cuid())
|
||||
sessionId String
|
||||
projectId String
|
||||
userId String
|
||||
score Int // 1-10
|
||||
votedAt DateTime @default(now())
|
||||
id String @id @default(cuid())
|
||||
sessionId String
|
||||
projectId String
|
||||
userId String
|
||||
score Int // 1-10
|
||||
isAudienceVote Boolean @default(false)
|
||||
votedAt DateTime @default(now())
|
||||
|
||||
// Relations
|
||||
session LiveVotingSession @relation(fields: [sessionId], references: [id], onDelete: Cascade)
|
||||
@@ -1047,9 +1105,15 @@ model MentorAssignment {
|
||||
expertiseMatchScore Float?
|
||||
aiReasoning String? @db.Text
|
||||
|
||||
// Tracking
|
||||
completionStatus String @default("in_progress") // 'in_progress' | 'completed' | 'paused'
|
||||
lastViewedAt DateTime?
|
||||
|
||||
// Relations
|
||||
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
||||
mentor User @relation("MentorAssignments", fields: [mentorId], references: [id])
|
||||
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
||||
mentor User @relation("MentorAssignments", fields: [mentorId], references: [id])
|
||||
notes MentorNote[]
|
||||
milestoneCompletions MentorMilestoneCompletion[]
|
||||
|
||||
@@index([mentorId])
|
||||
@@index([method])
|
||||
@@ -1454,3 +1518,269 @@ model MentorMessage {
|
||||
|
||||
@@index([projectId, createdAt])
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// ROUND TEMPLATES
|
||||
// =============================================================================
|
||||
|
||||
model RoundTemplate {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
description String?
|
||||
programId String?
|
||||
roundType RoundType @default(EVALUATION)
|
||||
criteriaJson Json @db.JsonB
|
||||
settingsJson Json? @db.JsonB
|
||||
assignmentConfig Json? @db.JsonB
|
||||
createdBy String
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// Relations
|
||||
program Program? @relation(fields: [programId], references: [id], onDelete: Cascade)
|
||||
creator User @relation("RoundTemplateCreatedBy", fields: [createdBy], references: [id])
|
||||
|
||||
@@index([programId])
|
||||
@@index([roundType])
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// MENTOR NOTES & MILESTONES
|
||||
// =============================================================================
|
||||
|
||||
model MentorNote {
|
||||
id String @id @default(cuid())
|
||||
mentorAssignmentId String
|
||||
authorId String
|
||||
content String @db.Text
|
||||
isVisibleToAdmin Boolean @default(true)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// Relations
|
||||
mentorAssignment MentorAssignment @relation(fields: [mentorAssignmentId], references: [id], onDelete: Cascade)
|
||||
author User @relation("MentorNoteAuthor", fields: [authorId], references: [id])
|
||||
|
||||
@@index([mentorAssignmentId])
|
||||
@@index([authorId])
|
||||
}
|
||||
|
||||
model MentorMilestone {
|
||||
id String @id @default(cuid())
|
||||
programId String
|
||||
name String
|
||||
description String? @db.Text
|
||||
isRequired Boolean @default(false)
|
||||
deadlineOffsetDays Int?
|
||||
sortOrder Int @default(0)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// Relations
|
||||
program Program @relation(fields: [programId], references: [id], onDelete: Cascade)
|
||||
completions MentorMilestoneCompletion[]
|
||||
|
||||
@@index([programId])
|
||||
@@index([sortOrder])
|
||||
}
|
||||
|
||||
model MentorMilestoneCompletion {
|
||||
milestoneId String
|
||||
mentorAssignmentId String
|
||||
completedById String
|
||||
completedAt DateTime @default(now())
|
||||
|
||||
// Relations
|
||||
milestone MentorMilestone @relation(fields: [milestoneId], references: [id], onDelete: Cascade)
|
||||
mentorAssignment MentorAssignment @relation(fields: [mentorAssignmentId], references: [id], onDelete: Cascade)
|
||||
completedBy User @relation("MilestoneCompletedBy", fields: [completedById], references: [id])
|
||||
|
||||
@@id([milestoneId, mentorAssignmentId])
|
||||
@@index([mentorAssignmentId])
|
||||
@@index([completedById])
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// EVALUATION DISCUSSIONS
|
||||
// =============================================================================
|
||||
|
||||
model EvaluationDiscussion {
|
||||
id String @id @default(cuid())
|
||||
projectId String
|
||||
roundId String
|
||||
status String @default("open") // 'open' | 'closed'
|
||||
closedAt DateTime?
|
||||
closedById String?
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// Relations
|
||||
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
||||
round Round @relation(fields: [roundId], references: [id], onDelete: Cascade)
|
||||
closedBy User? @relation("DiscussionClosedBy", fields: [closedById], references: [id], onDelete: SetNull)
|
||||
comments DiscussionComment[]
|
||||
|
||||
@@unique([projectId, roundId])
|
||||
@@index([roundId])
|
||||
@@index([closedById])
|
||||
}
|
||||
|
||||
model DiscussionComment {
|
||||
id String @id @default(cuid())
|
||||
discussionId String
|
||||
userId String
|
||||
content String @db.Text
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
// Relations
|
||||
discussion EvaluationDiscussion @relation(fields: [discussionId], references: [id], onDelete: Cascade)
|
||||
user User @relation("DiscussionCommentAuthor", fields: [userId], references: [id])
|
||||
|
||||
@@index([discussionId])
|
||||
@@index([userId])
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// MESSAGING SYSTEM
|
||||
// =============================================================================
|
||||
|
||||
model Message {
|
||||
id String @id @default(cuid())
|
||||
senderId String
|
||||
recipientType String // 'USER', 'ROLE', 'ROUND_JURY', 'PROGRAM_TEAM', 'ALL'
|
||||
recipientFilter Json? @db.JsonB
|
||||
roundId String?
|
||||
templateId String?
|
||||
subject String
|
||||
body String @db.Text
|
||||
deliveryChannels String[]
|
||||
|
||||
scheduledAt DateTime?
|
||||
sentAt DateTime?
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// Relations
|
||||
sender User @relation("MessageSender", fields: [senderId], references: [id], onDelete: Cascade)
|
||||
round Round? @relation(fields: [roundId], references: [id], onDelete: SetNull)
|
||||
template MessageTemplate? @relation(fields: [templateId], references: [id], onDelete: SetNull)
|
||||
recipients MessageRecipient[]
|
||||
|
||||
@@index([senderId])
|
||||
@@index([roundId])
|
||||
@@index([sentAt])
|
||||
}
|
||||
|
||||
model MessageRecipient {
|
||||
id String @id @default(cuid())
|
||||
messageId String
|
||||
userId String
|
||||
channel String // 'EMAIL', 'IN_APP', etc.
|
||||
isRead Boolean @default(false)
|
||||
readAt DateTime?
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// Relations
|
||||
message Message @relation(fields: [messageId], references: [id], onDelete: Cascade)
|
||||
user User @relation("MessageRecipient", fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([messageId, userId, channel])
|
||||
@@index([userId])
|
||||
}
|
||||
|
||||
model MessageTemplate {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
category String // 'SYSTEM', 'EVALUATION', 'ASSIGNMENT'
|
||||
subject String
|
||||
body String @db.Text
|
||||
variables Json? @db.JsonB
|
||||
createdById String
|
||||
isActive Boolean @default(true)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// Relations
|
||||
createdBy User @relation("MessageTemplateCreator", fields: [createdById], references: [id], onDelete: Cascade)
|
||||
messages Message[]
|
||||
|
||||
@@index([category])
|
||||
@@index([isActive])
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// WEBHOOKS
|
||||
// =============================================================================
|
||||
|
||||
model Webhook {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
url String
|
||||
secret String
|
||||
events String[]
|
||||
headers Json? @db.JsonB
|
||||
maxRetries Int @default(3)
|
||||
isActive Boolean @default(true)
|
||||
createdById String
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// Relations
|
||||
createdBy User @relation("WebhookCreator", fields: [createdById], references: [id], onDelete: Cascade)
|
||||
deliveries WebhookDelivery[]
|
||||
|
||||
@@index([isActive])
|
||||
@@index([createdById])
|
||||
}
|
||||
|
||||
model WebhookDelivery {
|
||||
id String @id @default(cuid())
|
||||
webhookId String
|
||||
event String
|
||||
payload Json @db.JsonB
|
||||
status String @default("PENDING") // 'PENDING', 'DELIVERED', 'FAILED'
|
||||
responseStatus Int?
|
||||
responseBody String? @db.Text
|
||||
attempts Int @default(0)
|
||||
lastAttemptAt DateTime?
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// Relations
|
||||
webhook Webhook @relation(fields: [webhookId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([webhookId])
|
||||
@@index([status])
|
||||
@@index([event])
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// DIGEST LOGS
|
||||
// =============================================================================
|
||||
|
||||
model DigestLog {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
digestType String // 'daily' | 'weekly'
|
||||
contentJson Json @db.JsonB
|
||||
sentAt DateTime @default(now())
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// Relations
|
||||
user User @relation("DigestLog", fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([userId, sentAt])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user