Reconcile schema with migrations and fix failed migration

- Align schema.prisma with add_15_features migration (15 discrepancies):
  nullability, column names, PKs, missing/extra columns, onDelete behavior
- Make universal_apply_programid migration idempotent for safe re-execution
- Add reconciliation migration for missing FKs and indexes
- Fix message.ts and mentor.ts to match corrected schema field names

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-08 14:37:32 +01:00
parent 04d0deced1
commit e0e4cb2a32
18 changed files with 1174 additions and 353 deletions

View File

@@ -114,6 +114,8 @@ enum SettingCategory {
LOCALIZATION
DIGEST
ANALYTICS
INTEGRATIONS
COMMUNICATION
}
enum NotificationChannel {
@@ -227,7 +229,7 @@ model User {
inviteTokenExpiresAt DateTime?
// Digest & availability preferences
digestFrequency String? // 'none' | 'daily' | 'weekly'
digestFrequency String @default("none") // 'none' | 'daily' | 'weekly'
preferredWorkload Int?
availabilityJson Json? @db.JsonB // { startDate?: string, endDate?: string }
@@ -749,7 +751,8 @@ model AuditLog {
entityId String?
// Details
detailsJson Json? @db.JsonB // Before/after values, additional context
detailsJson Json? @db.JsonB // Before/after values, additional context
previousDataJson Json? @db.JsonB // Previous state for tracking changes
// Request info
ipAddress String?
@@ -1031,8 +1034,8 @@ model LiveVotingSession {
// Audience & presentation settings
allowAudienceVotes Boolean @default(false)
audienceVoteWeight Float? // 0.0 to 1.0
tieBreakerMethod String? // 'admin_decides' | 'highest_individual' | 'revote'
audienceVoteWeight Float @default(0) // 0.0 to 1.0
tieBreakerMethod String @default("admin_decides") // 'admin_decides' | 'highest_individual' | 'revote'
presentationSettingsJson Json? @db.JsonB
createdAt DateTime @default(now())
@@ -1588,6 +1591,7 @@ model MentorMilestone {
}
model MentorMilestoneCompletion {
id String @id @default(cuid())
milestoneId String
mentorAssignmentId String
completedById String
@@ -1598,7 +1602,7 @@ model MentorMilestoneCompletion {
mentorAssignment MentorAssignment @relation(fields: [mentorAssignmentId], references: [id], onDelete: Cascade)
completedBy User @relation("MilestoneCompletedBy", fields: [completedById], references: [id])
@@id([milestoneId, mentorAssignmentId])
@@unique([milestoneId, mentorAssignmentId])
@@index([mentorAssignmentId])
@@index([completedById])
}
@@ -1612,12 +1616,10 @@ model EvaluationDiscussion {
projectId String
roundId String
status String @default("open") // 'open' | 'closed'
createdAt DateTime @default(now())
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)
@@ -1662,12 +1664,12 @@ model Message {
scheduledAt DateTime?
sentAt DateTime?
metadata Json? @db.JsonB
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
sender User @relation("MessageSender", fields: [senderId], references: [id], onDelete: Cascade)
sender User @relation("MessageSender", fields: [senderId], references: [id])
round Round? @relation(fields: [roundId], references: [id], onDelete: SetNull)
template MessageTemplate? @relation(fields: [templateId], references: [id], onDelete: SetNull)
recipients MessageRecipient[]
@@ -1678,15 +1680,13 @@ model Message {
}
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
id String @id @default(cuid())
messageId String
userId String
channel String // 'EMAIL', 'IN_APP', etc.
isRead Boolean @default(false)
readAt DateTime?
deliveredAt DateTime?
// Relations
message Message @relation(fields: [messageId], references: [id], onDelete: Cascade)
@@ -1697,21 +1697,21 @@ model MessageRecipient {
}
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)
id String @id @default(cuid())
name String
category String // 'SYSTEM', 'EVALUATION', 'ASSIGNMENT'
subject String
body String @db.Text
variables Json? @db.JsonB
isActive Boolean @default(true)
createdBy String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
createdBy User @relation("MessageTemplateCreator", fields: [createdById], references: [id], onDelete: Cascade)
messages Message[]
creator User @relation("MessageTemplateCreator", fields: [createdBy], references: [id])
messages Message[]
@@index([category])
@@index([isActive])
@@ -1736,7 +1736,7 @@ model Webhook {
updatedAt DateTime @updatedAt
// Relations
createdBy User @relation("WebhookCreator", fields: [createdById], references: [id], onDelete: Cascade)
createdBy User @relation("WebhookCreator", fields: [createdById], references: [id])
deliveries WebhookDelivery[]
@@index([isActive])
@@ -1755,7 +1755,6 @@ model WebhookDelivery {
lastAttemptAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
webhook Webhook @relation(fields: [webhookId], references: [id], onDelete: Cascade)
@@ -1776,11 +1775,9 @@ model DigestLog {
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])
@@index([userId])
@@index([sentAt])
}