Remove dynamic form builder and complete RoundProject→roundId migration
Major cleanup and schema migration: - Remove unused dynamic form builder system (ApplicationForm, ApplicationFormField, etc.) - Complete migration from RoundProject junction table to direct Project.roundId - Add sortOrder and entryNotificationType fields to Round model - Add country field to User model for mentor matching - Enhance onboarding with profile photo and country selection steps - Fix all TypeScript errors related to roundProjects references - Remove unused libraries (@radix-ui/react-toast, embla-carousel-react, vaul) Files removed: - admin/forms/* pages and related components - admin/onboarding/* pages - applicationForm.ts and onboarding.ts routers - Dynamic form builder Prisma models and enums Schema changes: - Removed ApplicationForm, ApplicationFormField, OnboardingStep, ApplicationFormSubmission, SubmissionFile models - Removed FormFieldType and SpecialFieldType enums - Added Round.sortOrder, Round.entryNotificationType - Added User.country Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -147,35 +147,6 @@ enum PartnerType {
|
||||
OTHER
|
||||
}
|
||||
|
||||
enum FormFieldType {
|
||||
TEXT
|
||||
TEXTAREA
|
||||
NUMBER
|
||||
EMAIL
|
||||
PHONE
|
||||
URL
|
||||
DATE
|
||||
DATETIME
|
||||
SELECT
|
||||
MULTI_SELECT
|
||||
RADIO
|
||||
CHECKBOX
|
||||
CHECKBOX_GROUP
|
||||
FILE
|
||||
FILE_MULTIPLE
|
||||
SECTION
|
||||
INSTRUCTIONS
|
||||
}
|
||||
|
||||
enum SpecialFieldType {
|
||||
TEAM_MEMBERS // Team member repeater
|
||||
COMPETITION_CATEGORY // Business Concept vs Startup
|
||||
OCEAN_ISSUE // Ocean issue dropdown
|
||||
FILE_UPLOAD // File upload
|
||||
GDPR_CONSENT // GDPR consent checkbox
|
||||
COUNTRY_SELECT // Country dropdown
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// APPLICANT SYSTEM ENUMS
|
||||
// =============================================================================
|
||||
@@ -225,6 +196,7 @@ model User {
|
||||
status UserStatus @default(INVITED)
|
||||
expertiseTags String[] @default([])
|
||||
maxAssignments Int? // Per-round limit
|
||||
country String? // User's home country (for mentor matching)
|
||||
metadataJson Json? @db.JsonB
|
||||
|
||||
// Profile image
|
||||
@@ -348,10 +320,8 @@ model Program {
|
||||
|
||||
// Relations
|
||||
rounds Round[]
|
||||
projects Project[]
|
||||
learningResources LearningResource[]
|
||||
partners Partner[]
|
||||
applicationForms ApplicationForm[]
|
||||
specialAwards SpecialAward[]
|
||||
|
||||
@@unique([name, year])
|
||||
@@ -365,7 +335,10 @@ model Round {
|
||||
slug String? @unique // URL-friendly identifier for public submissions
|
||||
status RoundStatus @default(DRAFT)
|
||||
roundType RoundType @default(EVALUATION)
|
||||
sortOrder Int @default(0) // Progression order within program
|
||||
sortOrder Int @default(0) // Display order within program
|
||||
|
||||
// Entry notification settings
|
||||
entryNotificationType String? // Type of notification to send when project enters round
|
||||
|
||||
// Submission window (for applicant portal)
|
||||
submissionDeadline DateTime? // Deadline for project submissions
|
||||
@@ -385,15 +358,12 @@ model Round {
|
||||
requiredReviews Int @default(3) // Min evaluations per project
|
||||
settingsJson Json? @db.JsonB // Grace periods, visibility rules, etc.
|
||||
|
||||
// Notification sent to project team when they enter this round
|
||||
entryNotificationType String? // e.g., "ADVANCED_SEMIFINAL", "ADVANCED_FINAL"
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// Relations
|
||||
program Program @relation(fields: [programId], references: [id], onDelete: Cascade)
|
||||
roundProjects RoundProject[]
|
||||
projects Project[]
|
||||
assignments Assignment[]
|
||||
evaluationForms EvaluationForm[]
|
||||
gracePeriods GracePeriod[]
|
||||
@@ -401,7 +371,6 @@ model Round {
|
||||
filteringRules FilteringRule[]
|
||||
filteringResults FilteringResult[]
|
||||
filteringJobs FilteringJob[]
|
||||
applicationForm ApplicationForm?
|
||||
|
||||
@@index([programId])
|
||||
@@index([status])
|
||||
@@ -439,7 +408,8 @@ model EvaluationForm {
|
||||
|
||||
model Project {
|
||||
id String @id @default(cuid())
|
||||
programId String
|
||||
roundId String
|
||||
status ProjectStatus @default(SUBMITTED)
|
||||
|
||||
// Core fields
|
||||
title String
|
||||
@@ -493,8 +463,7 @@ model Project {
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// Relations
|
||||
program Program @relation(fields: [programId], references: [id], onDelete: Cascade)
|
||||
roundProjects RoundProject[]
|
||||
round Round @relation(fields: [roundId], references: [id], onDelete: Cascade)
|
||||
files ProjectFile[]
|
||||
assignments Assignment[]
|
||||
submittedBy User? @relation("ProjectSubmittedBy", fields: [submittedByUserId], references: [id], onDelete: SetNull)
|
||||
@@ -504,8 +473,10 @@ model Project {
|
||||
awardEligibilities AwardEligibility[]
|
||||
awardVotes AwardVote[]
|
||||
wonAwards SpecialAward[] @relation("AwardWinner")
|
||||
projectTags ProjectTag[]
|
||||
|
||||
@@index([programId])
|
||||
@@index([roundId])
|
||||
@@index([status])
|
||||
@@index([tags])
|
||||
@@index([submissionSource])
|
||||
@@index([submittedByUserId])
|
||||
@@ -514,23 +485,6 @@ model Project {
|
||||
@@index([country])
|
||||
}
|
||||
|
||||
model RoundProject {
|
||||
id String @id @default(cuid())
|
||||
roundId String
|
||||
projectId String
|
||||
status ProjectStatus @default(SUBMITTED)
|
||||
addedAt DateTime @default(now())
|
||||
|
||||
// Relations
|
||||
round Round @relation(fields: [roundId], references: [id], onDelete: Cascade)
|
||||
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([roundId, projectId])
|
||||
@@index([roundId])
|
||||
@@index([projectId])
|
||||
@@index([status])
|
||||
}
|
||||
|
||||
model ProjectFile {
|
||||
id String @id @default(cuid())
|
||||
projectId String
|
||||
@@ -906,149 +860,6 @@ model Partner {
|
||||
@@index([sortOrder])
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// APPLICATION FORMS (Phase 2)
|
||||
// =============================================================================
|
||||
|
||||
model ApplicationForm {
|
||||
id String @id @default(cuid())
|
||||
programId String? // null = global form
|
||||
name String
|
||||
description String? @db.Text
|
||||
status String @default("DRAFT") // DRAFT, PUBLISHED, CLOSED
|
||||
|
||||
isPublic Boolean @default(false)
|
||||
publicSlug String? @unique // /apply/ocean-challenge-2026
|
||||
submissionLimit Int?
|
||||
opensAt DateTime?
|
||||
closesAt DateTime?
|
||||
|
||||
confirmationMessage String? @db.Text
|
||||
|
||||
// Round linking (for onboarding forms that create projects)
|
||||
roundId String? @unique
|
||||
|
||||
// Email settings
|
||||
sendConfirmationEmail Boolean @default(true)
|
||||
sendTeamInviteEmails Boolean @default(true)
|
||||
confirmationEmailSubject String?
|
||||
confirmationEmailBody String? @db.Text
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// Relations
|
||||
program Program? @relation(fields: [programId], references: [id], onDelete: SetNull)
|
||||
round Round? @relation(fields: [roundId], references: [id], onDelete: SetNull)
|
||||
fields ApplicationFormField[]
|
||||
steps OnboardingStep[]
|
||||
submissions ApplicationFormSubmission[]
|
||||
|
||||
@@index([programId])
|
||||
@@index([status])
|
||||
@@index([isPublic])
|
||||
@@index([roundId])
|
||||
}
|
||||
|
||||
model ApplicationFormField {
|
||||
id String @id @default(cuid())
|
||||
formId String
|
||||
stepId String? // Which step this field belongs to (for onboarding)
|
||||
fieldType FormFieldType
|
||||
name String // Internal name (e.g., "project_title")
|
||||
label String // Display label (e.g., "Project Title")
|
||||
description String? @db.Text
|
||||
placeholder String?
|
||||
|
||||
required Boolean @default(false)
|
||||
minLength Int?
|
||||
maxLength Int?
|
||||
minValue Float? // For NUMBER type
|
||||
maxValue Float? // For NUMBER type
|
||||
|
||||
optionsJson Json? @db.JsonB // For select/radio: [{ value, label }]
|
||||
conditionJson Json? @db.JsonB // Conditional logic: { fieldId, operator, value }
|
||||
|
||||
// Onboarding-specific fields
|
||||
projectMapping String? // Maps to Project column: "title", "description", etc.
|
||||
specialType SpecialFieldType? // Special handling for complex fields
|
||||
|
||||
sortOrder Int @default(0)
|
||||
width String @default("full") // full, half
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// Relations
|
||||
form ApplicationForm @relation(fields: [formId], references: [id], onDelete: Cascade)
|
||||
step OnboardingStep? @relation(fields: [stepId], references: [id], onDelete: SetNull)
|
||||
|
||||
@@index([formId])
|
||||
@@index([stepId])
|
||||
@@index([sortOrder])
|
||||
}
|
||||
|
||||
model OnboardingStep {
|
||||
id String @id @default(cuid())
|
||||
formId String
|
||||
name String // Internal identifier (e.g., "category", "contact")
|
||||
title String // Display title (e.g., "Category", "Contact Information")
|
||||
description String? @db.Text
|
||||
sortOrder Int @default(0)
|
||||
isOptional Boolean @default(false)
|
||||
conditionJson Json? @db.JsonB // Conditional visibility: { fieldId, operator, value }
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// Relations
|
||||
form ApplicationForm @relation(fields: [formId], references: [id], onDelete: Cascade)
|
||||
fields ApplicationFormField[]
|
||||
|
||||
@@index([formId])
|
||||
@@index([sortOrder])
|
||||
}
|
||||
|
||||
model ApplicationFormSubmission {
|
||||
id String @id @default(cuid())
|
||||
formId String
|
||||
email String?
|
||||
name String?
|
||||
dataJson Json @db.JsonB // Field values: { fieldName: value, ... }
|
||||
status String @default("SUBMITTED") // SUBMITTED, REVIEWED, APPROVED, REJECTED
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// Relations
|
||||
form ApplicationForm @relation(fields: [formId], references: [id], onDelete: Cascade)
|
||||
files SubmissionFile[]
|
||||
|
||||
@@index([formId])
|
||||
@@index([status])
|
||||
@@index([email])
|
||||
@@index([createdAt])
|
||||
}
|
||||
|
||||
model SubmissionFile {
|
||||
id String @id @default(cuid())
|
||||
submissionId String
|
||||
fieldName String
|
||||
fileName String
|
||||
mimeType String?
|
||||
size Int?
|
||||
bucket String
|
||||
objectKey String
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
// Relations
|
||||
submission ApplicationFormSubmission @relation(fields: [submissionId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([submissionId])
|
||||
@@unique([bucket, objectKey])
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// EXPERTISE TAGS (Phase 2B)
|
||||
// =============================================================================
|
||||
@@ -1065,11 +876,32 @@ model ExpertiseTag {
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// Relations
|
||||
projectTags ProjectTag[]
|
||||
|
||||
@@index([category])
|
||||
@@index([isActive])
|
||||
@@index([sortOrder])
|
||||
}
|
||||
|
||||
// Project-Tag relationship for AI tagging
|
||||
model ProjectTag {
|
||||
id String @id @default(cuid())
|
||||
projectId String
|
||||
tagId String
|
||||
confidence Float @default(1.0) // AI confidence score 0-1
|
||||
source String @default("AI") // "AI" or "MANUAL"
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
// Relations
|
||||
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
||||
tag ExpertiseTag @relation(fields: [tagId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([projectId, tagId])
|
||||
@@index([projectId])
|
||||
@@index([tagId])
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// LIVE VOTING (Phase 2B)
|
||||
// =============================================================================
|
||||
|
||||
Reference in New Issue
Block a user