Competition/Round architecture: full platform rewrite (Phases 1-9)
All checks were successful
Build and Push Docker Image / build (push) Successful in 7m45s
All checks were successful
Build and Push Docker Image / build (push) Successful in 7m45s
Replace Pipeline/Stage system with Competition/Round architecture. New schema: Competition, Round (7 types), JuryGroup, AssignmentPolicy, ProjectRoundState, DeliberationSession, ResultLock, SubmissionWindow. New services: round-engine, round-assignment, deliberation, result-lock, submission-manager, competition-context, ai-prompt-guard. Full admin/jury/applicant/mentor UI rewrite. AI prompt hardening with structured prompts, retry logic, and injection detection. All legacy pipeline/stage code removed. 4 new migrations + seed aligned. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,91 +1,91 @@
|
||||
-- Universal Apply Page: Make Project.roundId nullable and add programId FK
|
||||
-- This migration enables projects to be submitted to a program/edition without being assigned to a specific round
|
||||
-- NOTE: Written to be idempotent (safe to re-run if partially applied)
|
||||
|
||||
-- Step 1: Add Program.slug for edition-wide apply URLs (nullable for existing programs)
|
||||
ALTER TABLE "Program" ADD COLUMN IF NOT EXISTS "slug" TEXT;
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "Program_slug_key" ON "Program"("slug");
|
||||
|
||||
-- Step 2: Add programId column (nullable initially to handle existing data)
|
||||
ALTER TABLE "Project" ADD COLUMN IF NOT EXISTS "programId" TEXT;
|
||||
|
||||
-- Step 3: Backfill programId from existing round relationships
|
||||
-- Only update rows where programId is still NULL (idempotent)
|
||||
UPDATE "Project" p
|
||||
SET "programId" = r."programId"
|
||||
FROM "Round" r
|
||||
WHERE p."roundId" = r.id
|
||||
AND p."programId" IS NULL;
|
||||
|
||||
-- Step 4: Handle orphaned projects (no roundId = no way to derive programId)
|
||||
-- Assign them to the first available program, or delete them if no program exists
|
||||
DO $$
|
||||
DECLARE
|
||||
null_count INTEGER;
|
||||
fallback_program_id TEXT;
|
||||
BEGIN
|
||||
SELECT COUNT(*) INTO null_count FROM "Project" WHERE "programId" IS NULL;
|
||||
IF null_count > 0 THEN
|
||||
SELECT id INTO fallback_program_id FROM "Program" ORDER BY "createdAt" ASC LIMIT 1;
|
||||
IF fallback_program_id IS NOT NULL THEN
|
||||
UPDATE "Project" SET "programId" = fallback_program_id WHERE "programId" IS NULL;
|
||||
RAISE NOTICE 'Assigned % orphaned projects to fallback program %', null_count, fallback_program_id;
|
||||
ELSE
|
||||
DELETE FROM "Project" WHERE "programId" IS NULL;
|
||||
RAISE NOTICE 'Deleted % orphaned projects (no program exists to assign them to)', null_count;
|
||||
END IF;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Step 5: Make programId required (NOT NULL constraint) - safe if already NOT NULL
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'Project' AND column_name = 'programId' AND is_nullable = 'YES'
|
||||
) THEN
|
||||
ALTER TABLE "Project" ALTER COLUMN "programId" SET NOT NULL;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Step 6: Add foreign key constraint for programId (skip if already exists)
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.table_constraints
|
||||
WHERE constraint_name = 'Project_programId_fkey' AND table_name = 'Project'
|
||||
) THEN
|
||||
ALTER TABLE "Project" ADD CONSTRAINT "Project_programId_fkey"
|
||||
FOREIGN KEY ("programId") REFERENCES "Program"("id") ON DELETE CASCADE;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Step 7: Make roundId nullable (allow projects without round assignment)
|
||||
-- Safe: DROP NOT NULL is idempotent if already nullable
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'Project' AND column_name = 'roundId' AND is_nullable = 'NO'
|
||||
) THEN
|
||||
ALTER TABLE "Project" ALTER COLUMN "roundId" DROP NOT NULL;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Step 8: Update round FK to SET NULL on delete (instead of CASCADE)
|
||||
-- Projects should remain in the database if their round is deleted
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM information_schema.table_constraints
|
||||
WHERE constraint_name = 'Project_roundId_fkey' AND table_name = 'Project'
|
||||
) THEN
|
||||
ALTER TABLE "Project" DROP CONSTRAINT "Project_roundId_fkey";
|
||||
END IF;
|
||||
ALTER TABLE "Project" ADD CONSTRAINT "Project_roundId_fkey"
|
||||
FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE SET NULL;
|
||||
END $$;
|
||||
|
||||
-- Step 9: Add performance indexes
|
||||
CREATE INDEX IF NOT EXISTS "Project_programId_idx" ON "Project"("programId");
|
||||
CREATE INDEX IF NOT EXISTS "Project_programId_roundId_idx" ON "Project"("programId", "roundId");
|
||||
-- Universal Apply Page: Make Project.roundId nullable and add programId FK
|
||||
-- This migration enables projects to be submitted to a program/edition without being assigned to a specific round
|
||||
-- NOTE: Written to be idempotent (safe to re-run if partially applied)
|
||||
|
||||
-- Step 1: Add Program.slug for edition-wide apply URLs (nullable for existing programs)
|
||||
ALTER TABLE "Program" ADD COLUMN IF NOT EXISTS "slug" TEXT;
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "Program_slug_key" ON "Program"("slug");
|
||||
|
||||
-- Step 2: Add programId column (nullable initially to handle existing data)
|
||||
ALTER TABLE "Project" ADD COLUMN IF NOT EXISTS "programId" TEXT;
|
||||
|
||||
-- Step 3: Backfill programId from existing round relationships
|
||||
-- Only update rows where programId is still NULL (idempotent)
|
||||
UPDATE "Project" p
|
||||
SET "programId" = r."programId"
|
||||
FROM "Round" r
|
||||
WHERE p."roundId" = r.id
|
||||
AND p."programId" IS NULL;
|
||||
|
||||
-- Step 4: Handle orphaned projects (no roundId = no way to derive programId)
|
||||
-- Assign them to the first available program, or delete them if no program exists
|
||||
DO $$
|
||||
DECLARE
|
||||
null_count INTEGER;
|
||||
fallback_program_id TEXT;
|
||||
BEGIN
|
||||
SELECT COUNT(*) INTO null_count FROM "Project" WHERE "programId" IS NULL;
|
||||
IF null_count > 0 THEN
|
||||
SELECT id INTO fallback_program_id FROM "Program" ORDER BY "createdAt" ASC LIMIT 1;
|
||||
IF fallback_program_id IS NOT NULL THEN
|
||||
UPDATE "Project" SET "programId" = fallback_program_id WHERE "programId" IS NULL;
|
||||
RAISE NOTICE 'Assigned % orphaned projects to fallback program %', null_count, fallback_program_id;
|
||||
ELSE
|
||||
DELETE FROM "Project" WHERE "programId" IS NULL;
|
||||
RAISE NOTICE 'Deleted % orphaned projects (no program exists to assign them to)', null_count;
|
||||
END IF;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Step 5: Make programId required (NOT NULL constraint) - safe if already NOT NULL
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'Project' AND column_name = 'programId' AND is_nullable = 'YES'
|
||||
) THEN
|
||||
ALTER TABLE "Project" ALTER COLUMN "programId" SET NOT NULL;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Step 6: Add foreign key constraint for programId (skip if already exists)
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.table_constraints
|
||||
WHERE constraint_name = 'Project_programId_fkey' AND table_name = 'Project'
|
||||
) THEN
|
||||
ALTER TABLE "Project" ADD CONSTRAINT "Project_programId_fkey"
|
||||
FOREIGN KEY ("programId") REFERENCES "Program"("id") ON DELETE CASCADE;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Step 7: Make roundId nullable (allow projects without round assignment)
|
||||
-- Safe: DROP NOT NULL is idempotent if already nullable
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'Project' AND column_name = 'roundId' AND is_nullable = 'NO'
|
||||
) THEN
|
||||
ALTER TABLE "Project" ALTER COLUMN "roundId" DROP NOT NULL;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Step 8: Update round FK to SET NULL on delete (instead of CASCADE)
|
||||
-- Projects should remain in the database if their round is deleted
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM information_schema.table_constraints
|
||||
WHERE constraint_name = 'Project_roundId_fkey' AND table_name = 'Project'
|
||||
) THEN
|
||||
ALTER TABLE "Project" DROP CONSTRAINT "Project_roundId_fkey";
|
||||
END IF;
|
||||
ALTER TABLE "Project" ADD CONSTRAINT "Project_roundId_fkey"
|
||||
FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE SET NULL;
|
||||
END $$;
|
||||
|
||||
-- Step 9: Add performance indexes
|
||||
CREATE INDEX IF NOT EXISTS "Project_programId_idx" ON "Project"("programId");
|
||||
CREATE INDEX IF NOT EXISTS "Project_programId_roundId_idx" ON "Project"("programId", "roundId");
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
-- Reconciliation migration: Add missing foreign keys and indexes
|
||||
-- The add_15_features migration omitted some FKs and indexes that the schema expects
|
||||
-- This migration brings the database in line with the Prisma schema
|
||||
|
||||
-- =====================================================
|
||||
-- Missing Foreign Keys
|
||||
-- =====================================================
|
||||
|
||||
-- RoundTemplate → Program
|
||||
ALTER TABLE "RoundTemplate" ADD CONSTRAINT "RoundTemplate_programId_fkey"
|
||||
FOREIGN KEY ("programId") REFERENCES "Program"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- RoundTemplate → User (creator)
|
||||
ALTER TABLE "RoundTemplate" ADD CONSTRAINT "RoundTemplate_createdBy_fkey"
|
||||
FOREIGN KEY ("createdBy") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- Message → Round
|
||||
ALTER TABLE "Message" ADD CONSTRAINT "Message_roundId_fkey"
|
||||
FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- EvaluationDiscussion → Round
|
||||
ALTER TABLE "EvaluationDiscussion" ADD CONSTRAINT "EvaluationDiscussion_roundId_fkey"
|
||||
FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- ProjectFile → ProjectFile (self-relation for file versioning)
|
||||
ALTER TABLE "ProjectFile" ADD CONSTRAINT "ProjectFile_replacedById_fkey"
|
||||
FOREIGN KEY ("replacedById") REFERENCES "ProjectFile"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- =====================================================
|
||||
-- Missing Indexes
|
||||
-- =====================================================
|
||||
|
||||
CREATE INDEX "RoundTemplate_roundType_idx" ON "RoundTemplate"("roundType");
|
||||
CREATE INDEX "MentorNote_authorId_idx" ON "MentorNote"("authorId");
|
||||
CREATE INDEX "MentorMilestoneCompletion_completedById_idx" ON "MentorMilestoneCompletion"("completedById");
|
||||
CREATE INDEX "Webhook_createdById_idx" ON "Webhook"("createdById");
|
||||
CREATE INDEX "WebhookDelivery_event_idx" ON "WebhookDelivery"("event");
|
||||
CREATE INDEX "Message_roundId_idx" ON "Message"("roundId");
|
||||
CREATE INDEX "EvaluationDiscussion_closedById_idx" ON "EvaluationDiscussion"("closedById");
|
||||
CREATE INDEX "DiscussionComment_discussionId_idx" ON "DiscussionComment"("discussionId");
|
||||
CREATE INDEX "DiscussionComment_userId_idx" ON "DiscussionComment"("userId");
|
||||
-- Reconciliation migration: Add missing foreign keys and indexes
|
||||
-- The add_15_features migration omitted some FKs and indexes that the schema expects
|
||||
-- This migration brings the database in line with the Prisma schema
|
||||
|
||||
-- =====================================================
|
||||
-- Missing Foreign Keys
|
||||
-- =====================================================
|
||||
|
||||
-- RoundTemplate → Program
|
||||
ALTER TABLE "RoundTemplate" ADD CONSTRAINT "RoundTemplate_programId_fkey"
|
||||
FOREIGN KEY ("programId") REFERENCES "Program"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- RoundTemplate → User (creator)
|
||||
ALTER TABLE "RoundTemplate" ADD CONSTRAINT "RoundTemplate_createdBy_fkey"
|
||||
FOREIGN KEY ("createdBy") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- Message → Round
|
||||
ALTER TABLE "Message" ADD CONSTRAINT "Message_roundId_fkey"
|
||||
FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- EvaluationDiscussion → Round
|
||||
ALTER TABLE "EvaluationDiscussion" ADD CONSTRAINT "EvaluationDiscussion_roundId_fkey"
|
||||
FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- ProjectFile → ProjectFile (self-relation for file versioning)
|
||||
ALTER TABLE "ProjectFile" ADD CONSTRAINT "ProjectFile_replacedById_fkey"
|
||||
FOREIGN KEY ("replacedById") REFERENCES "ProjectFile"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- =====================================================
|
||||
-- Missing Indexes
|
||||
-- =====================================================
|
||||
|
||||
CREATE INDEX "RoundTemplate_roundType_idx" ON "RoundTemplate"("roundType");
|
||||
CREATE INDEX "MentorNote_authorId_idx" ON "MentorNote"("authorId");
|
||||
CREATE INDEX "MentorMilestoneCompletion_completedById_idx" ON "MentorMilestoneCompletion"("completedById");
|
||||
CREATE INDEX "Webhook_createdById_idx" ON "Webhook"("createdById");
|
||||
CREATE INDEX "WebhookDelivery_event_idx" ON "WebhookDelivery"("event");
|
||||
CREATE INDEX "Message_roundId_idx" ON "Message"("roundId");
|
||||
CREATE INDEX "EvaluationDiscussion_closedById_idx" ON "EvaluationDiscussion"("closedById");
|
||||
CREATE INDEX "DiscussionComment_discussionId_idx" ON "DiscussionComment"("discussionId");
|
||||
CREATE INDEX "DiscussionComment_userId_idx" ON "DiscussionComment"("userId");
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
-- Fix round deletion FK constraint errors
|
||||
-- Add CASCADE on Evaluation.formId so deleting EvaluationForm cascades to Evaluations
|
||||
-- Add SET NULL on ProjectFile.roundId so deleting Round nullifies the reference
|
||||
|
||||
-- AlterTable: Evaluation.formId -> onDelete CASCADE
|
||||
ALTER TABLE "Evaluation" DROP CONSTRAINT "Evaluation_formId_fkey";
|
||||
ALTER TABLE "Evaluation" ADD CONSTRAINT "Evaluation_formId_fkey"
|
||||
FOREIGN KEY ("formId") REFERENCES "EvaluationForm"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AlterTable: ProjectFile.roundId -> onDelete SET NULL
|
||||
ALTER TABLE "ProjectFile" DROP CONSTRAINT "ProjectFile_roundId_fkey";
|
||||
ALTER TABLE "ProjectFile" ADD CONSTRAINT "ProjectFile_roundId_fkey"
|
||||
FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
-- Fix round deletion FK constraint errors
|
||||
-- Add CASCADE on Evaluation.formId so deleting EvaluationForm cascades to Evaluations
|
||||
-- Add SET NULL on ProjectFile.roundId so deleting Round nullifies the reference
|
||||
|
||||
-- AlterTable: Evaluation.formId -> onDelete CASCADE
|
||||
ALTER TABLE "Evaluation" DROP CONSTRAINT "Evaluation_formId_fkey";
|
||||
ALTER TABLE "Evaluation" ADD CONSTRAINT "Evaluation_formId_fkey"
|
||||
FOREIGN KEY ("formId") REFERENCES "EvaluationForm"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AlterTable: ProjectFile.roundId -> onDelete SET NULL
|
||||
ALTER TABLE "ProjectFile" DROP CONSTRAINT "ProjectFile_roundId_fkey";
|
||||
ALTER TABLE "ProjectFile" ADD CONSTRAINT "ProjectFile_roundId_fkey"
|
||||
FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "FileRequirement" (
|
||||
"id" TEXT NOT NULL,
|
||||
"roundId" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"acceptedMimeTypes" TEXT[],
|
||||
"maxSizeMB" INTEGER,
|
||||
"isRequired" BOOLEAN NOT NULL DEFAULT true,
|
||||
"sortOrder" INTEGER NOT NULL DEFAULT 0,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "FileRequirement_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "FileRequirement_roundId_idx" ON "FileRequirement"("roundId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "FileRequirement" ADD CONSTRAINT "FileRequirement_roundId_fkey" FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AlterTable: add requirementId to ProjectFile
|
||||
ALTER TABLE "ProjectFile" ADD COLUMN "requirementId" TEXT;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ProjectFile_requirementId_idx" ON "ProjectFile"("requirementId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ProjectFile" ADD CONSTRAINT "ProjectFile_requirementId_fkey" FOREIGN KEY ("requirementId") REFERENCES "FileRequirement"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
-- CreateTable
|
||||
CREATE TABLE "FileRequirement" (
|
||||
"id" TEXT NOT NULL,
|
||||
"roundId" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"acceptedMimeTypes" TEXT[],
|
||||
"maxSizeMB" INTEGER,
|
||||
"isRequired" BOOLEAN NOT NULL DEFAULT true,
|
||||
"sortOrder" INTEGER NOT NULL DEFAULT 0,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "FileRequirement_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "FileRequirement_roundId_idx" ON "FileRequirement"("roundId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "FileRequirement" ADD CONSTRAINT "FileRequirement_roundId_fkey" FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AlterTable: add requirementId to ProjectFile
|
||||
ALTER TABLE "ProjectFile" ADD COLUMN "requirementId" TEXT;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ProjectFile_requirementId_idx" ON "ProjectFile"("requirementId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ProjectFile" ADD CONSTRAINT "ProjectFile_requirementId_fkey" FOREIGN KEY ("requirementId") REFERENCES "FileRequirement"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
@@ -1,129 +1,129 @@
|
||||
-- Migration: Add all missing schema elements not covered by previous migrations
|
||||
-- This brings the database fully in line with prisma/schema.prisma
|
||||
-- Uses IF NOT EXISTS / DO $$ guards for idempotent execution
|
||||
|
||||
-- =============================================================================
|
||||
-- 1. MISSING TABLE: WizardTemplate
|
||||
-- =============================================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "WizardTemplate" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"config" JSONB NOT NULL,
|
||||
"isGlobal" BOOLEAN NOT NULL DEFAULT false,
|
||||
"programId" TEXT,
|
||||
"createdBy" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "WizardTemplate_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "WizardTemplate_programId_idx" ON "WizardTemplate"("programId");
|
||||
CREATE INDEX IF NOT EXISTS "WizardTemplate_isGlobal_idx" ON "WizardTemplate"("isGlobal");
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "WizardTemplate" ADD CONSTRAINT "WizardTemplate_programId_fkey"
|
||||
FOREIGN KEY ("programId") REFERENCES "Program"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "WizardTemplate" ADD CONSTRAINT "WizardTemplate_createdBy_fkey"
|
||||
FOREIGN KEY ("createdBy") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||
|
||||
-- =============================================================================
|
||||
-- 2. MISSING COLUMNS ON SpecialAward: eligibility job tracking fields
|
||||
-- =============================================================================
|
||||
|
||||
ALTER TABLE "SpecialAward" ADD COLUMN IF NOT EXISTS "eligibilityJobStatus" TEXT;
|
||||
ALTER TABLE "SpecialAward" ADD COLUMN IF NOT EXISTS "eligibilityJobTotal" INTEGER;
|
||||
ALTER TABLE "SpecialAward" ADD COLUMN IF NOT EXISTS "eligibilityJobDone" INTEGER;
|
||||
ALTER TABLE "SpecialAward" ADD COLUMN IF NOT EXISTS "eligibilityJobError" TEXT;
|
||||
ALTER TABLE "SpecialAward" ADD COLUMN IF NOT EXISTS "eligibilityJobStarted" TIMESTAMP(3);
|
||||
|
||||
-- =============================================================================
|
||||
-- 3. Project.referralSource: Already in init migration. No action needed.
|
||||
-- Round.slug: Already in init migration. No action needed.
|
||||
-- =============================================================================
|
||||
|
||||
-- =============================================================================
|
||||
-- 5. MISSING INDEXES
|
||||
-- =============================================================================
|
||||
|
||||
-- 5a. Assignment: @@index([projectId, userId])
|
||||
CREATE INDEX IF NOT EXISTS "Assignment_projectId_userId_idx" ON "Assignment"("projectId", "userId");
|
||||
|
||||
-- 5b. AuditLog: @@index([sessionId])
|
||||
CREATE INDEX IF NOT EXISTS "AuditLog_sessionId_idx" ON "AuditLog"("sessionId");
|
||||
|
||||
-- 5c. ProjectFile: @@index([projectId, roundId])
|
||||
CREATE INDEX IF NOT EXISTS "ProjectFile_projectId_roundId_idx" ON "ProjectFile"("projectId", "roundId");
|
||||
|
||||
-- 5d. MessageRecipient: @@index([userId])
|
||||
CREATE INDEX IF NOT EXISTS "MessageRecipient_userId_idx" ON "MessageRecipient"("userId");
|
||||
|
||||
-- 5e. MessageRecipient: @@unique([messageId, userId, channel])
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "MessageRecipient_messageId_userId_channel_key" ON "MessageRecipient"("messageId", "userId", "channel");
|
||||
|
||||
-- 5f. AwardEligibility: @@index([awardId, eligible]) - composite index
|
||||
CREATE INDEX IF NOT EXISTS "AwardEligibility_awardId_eligible_idx" ON "AwardEligibility"("awardId", "eligible");
|
||||
|
||||
-- =============================================================================
|
||||
-- 6. REMOVE STALE INDEX: Message_scheduledAt_idx
|
||||
-- The schema does NOT have @@index([scheduledAt]) on Message.
|
||||
-- The add_15_features migration created it, but the schema doesn't list it.
|
||||
-- Leaving it as-is since it's harmless and could be useful.
|
||||
-- =============================================================================
|
||||
|
||||
-- =============================================================================
|
||||
-- 7. VERIFY: All models from add_15_features are present
|
||||
-- DigestLog, RoundTemplate, MentorNote, MentorMilestone,
|
||||
-- MentorMilestoneCompletion, Message, MessageTemplate, MessageRecipient,
|
||||
-- Webhook, WebhookDelivery, EvaluationDiscussion, DiscussionComment
|
||||
-- -> All confirmed created in 20260205223133_add_15_features migration.
|
||||
-- -> All FKs confirmed in add_15_features + 20260208000000_add_missing_fks_indexes.
|
||||
-- =============================================================================
|
||||
|
||||
-- =============================================================================
|
||||
-- 8. VERIFY: Existing tables from init and subsequent migrations
|
||||
-- All core tables (User, Account, Session, VerificationToken, Program, Round,
|
||||
-- EvaluationForm, Project, ProjectFile, Assignment, Evaluation, GracePeriod,
|
||||
-- SystemSettings, AuditLog, AIUsageLog, NotificationLog, InAppNotification,
|
||||
-- NotificationEmailSetting, LearningResource, ResourceAccess, Partner,
|
||||
-- ExpertiseTag, ProjectTag, LiveVotingSession, LiveVote, TeamMember,
|
||||
-- MentorAssignment, FilteringRule, FilteringResult, FilteringJob,
|
||||
-- AssignmentJob, TaggingJob, SpecialAward, AwardEligibility, AwardJuror,
|
||||
-- AwardVote, ReminderLog, ConflictOfInterest, EvaluationSummary,
|
||||
-- ProjectStatusHistory, MentorMessage, FileRequirement)
|
||||
-- -> All confirmed present in migrations.
|
||||
-- =============================================================================
|
||||
|
||||
-- =============================================================================
|
||||
-- SUMMARY OF CHANGES IN THIS MIGRATION:
|
||||
--
|
||||
-- NEW TABLE:
|
||||
-- - WizardTemplate (with programId FK, createdBy FK, indexes)
|
||||
--
|
||||
-- NEW COLUMNS:
|
||||
-- - SpecialAward.eligibilityJobStatus (TEXT, nullable)
|
||||
-- - SpecialAward.eligibilityJobTotal (INTEGER, nullable)
|
||||
-- - SpecialAward.eligibilityJobDone (INTEGER, nullable)
|
||||
-- - SpecialAward.eligibilityJobError (TEXT, nullable)
|
||||
-- - SpecialAward.eligibilityJobStarted (TIMESTAMP, nullable)
|
||||
--
|
||||
-- NEW INDEXES:
|
||||
-- - Assignment_projectId_userId_idx
|
||||
-- - AuditLog_sessionId_idx
|
||||
-- - ProjectFile_projectId_roundId_idx
|
||||
-- - MessageRecipient_userId_idx
|
||||
-- - MessageRecipient_messageId_userId_channel_key (UNIQUE)
|
||||
-- - AwardEligibility_awardId_eligible_idx
|
||||
-- - WizardTemplate_programId_idx
|
||||
-- - WizardTemplate_isGlobal_idx
|
||||
--
|
||||
-- NEW FOREIGN KEYS:
|
||||
-- - WizardTemplate_programId_fkey -> Program(id) ON DELETE CASCADE
|
||||
-- - WizardTemplate_createdBy_fkey -> User(id) ON DELETE RESTRICT
|
||||
-- =============================================================================
|
||||
-- Migration: Add all missing schema elements not covered by previous migrations
|
||||
-- This brings the database fully in line with prisma/schema.prisma
|
||||
-- Uses IF NOT EXISTS / DO $$ guards for idempotent execution
|
||||
|
||||
-- =============================================================================
|
||||
-- 1. MISSING TABLE: WizardTemplate
|
||||
-- =============================================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "WizardTemplate" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"config" JSONB NOT NULL,
|
||||
"isGlobal" BOOLEAN NOT NULL DEFAULT false,
|
||||
"programId" TEXT,
|
||||
"createdBy" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "WizardTemplate_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "WizardTemplate_programId_idx" ON "WizardTemplate"("programId");
|
||||
CREATE INDEX IF NOT EXISTS "WizardTemplate_isGlobal_idx" ON "WizardTemplate"("isGlobal");
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "WizardTemplate" ADD CONSTRAINT "WizardTemplate_programId_fkey"
|
||||
FOREIGN KEY ("programId") REFERENCES "Program"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "WizardTemplate" ADD CONSTRAINT "WizardTemplate_createdBy_fkey"
|
||||
FOREIGN KEY ("createdBy") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||
|
||||
-- =============================================================================
|
||||
-- 2. MISSING COLUMNS ON SpecialAward: eligibility job tracking fields
|
||||
-- =============================================================================
|
||||
|
||||
ALTER TABLE "SpecialAward" ADD COLUMN IF NOT EXISTS "eligibilityJobStatus" TEXT;
|
||||
ALTER TABLE "SpecialAward" ADD COLUMN IF NOT EXISTS "eligibilityJobTotal" INTEGER;
|
||||
ALTER TABLE "SpecialAward" ADD COLUMN IF NOT EXISTS "eligibilityJobDone" INTEGER;
|
||||
ALTER TABLE "SpecialAward" ADD COLUMN IF NOT EXISTS "eligibilityJobError" TEXT;
|
||||
ALTER TABLE "SpecialAward" ADD COLUMN IF NOT EXISTS "eligibilityJobStarted" TIMESTAMP(3);
|
||||
|
||||
-- =============================================================================
|
||||
-- 3. Project.referralSource: Already in init migration. No action needed.
|
||||
-- Round.slug: Already in init migration. No action needed.
|
||||
-- =============================================================================
|
||||
|
||||
-- =============================================================================
|
||||
-- 5. MISSING INDEXES
|
||||
-- =============================================================================
|
||||
|
||||
-- 5a. Assignment: @@index([projectId, userId])
|
||||
CREATE INDEX IF NOT EXISTS "Assignment_projectId_userId_idx" ON "Assignment"("projectId", "userId");
|
||||
|
||||
-- 5b. AuditLog: @@index([sessionId])
|
||||
CREATE INDEX IF NOT EXISTS "AuditLog_sessionId_idx" ON "AuditLog"("sessionId");
|
||||
|
||||
-- 5c. ProjectFile: @@index([projectId, roundId])
|
||||
CREATE INDEX IF NOT EXISTS "ProjectFile_projectId_roundId_idx" ON "ProjectFile"("projectId", "roundId");
|
||||
|
||||
-- 5d. MessageRecipient: @@index([userId])
|
||||
CREATE INDEX IF NOT EXISTS "MessageRecipient_userId_idx" ON "MessageRecipient"("userId");
|
||||
|
||||
-- 5e. MessageRecipient: @@unique([messageId, userId, channel])
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "MessageRecipient_messageId_userId_channel_key" ON "MessageRecipient"("messageId", "userId", "channel");
|
||||
|
||||
-- 5f. AwardEligibility: @@index([awardId, eligible]) - composite index
|
||||
CREATE INDEX IF NOT EXISTS "AwardEligibility_awardId_eligible_idx" ON "AwardEligibility"("awardId", "eligible");
|
||||
|
||||
-- =============================================================================
|
||||
-- 6. REMOVE STALE INDEX: Message_scheduledAt_idx
|
||||
-- The schema does NOT have @@index([scheduledAt]) on Message.
|
||||
-- The add_15_features migration created it, but the schema doesn't list it.
|
||||
-- Leaving it as-is since it's harmless and could be useful.
|
||||
-- =============================================================================
|
||||
|
||||
-- =============================================================================
|
||||
-- 7. VERIFY: All models from add_15_features are present
|
||||
-- DigestLog, RoundTemplate, MentorNote, MentorMilestone,
|
||||
-- MentorMilestoneCompletion, Message, MessageTemplate, MessageRecipient,
|
||||
-- Webhook, WebhookDelivery, EvaluationDiscussion, DiscussionComment
|
||||
-- -> All confirmed created in 20260205223133_add_15_features migration.
|
||||
-- -> All FKs confirmed in add_15_features + 20260208000000_add_missing_fks_indexes.
|
||||
-- =============================================================================
|
||||
|
||||
-- =============================================================================
|
||||
-- 8. VERIFY: Existing tables from init and subsequent migrations
|
||||
-- All core tables (User, Account, Session, VerificationToken, Program, Round,
|
||||
-- EvaluationForm, Project, ProjectFile, Assignment, Evaluation, GracePeriod,
|
||||
-- SystemSettings, AuditLog, AIUsageLog, NotificationLog, InAppNotification,
|
||||
-- NotificationEmailSetting, LearningResource, ResourceAccess, Partner,
|
||||
-- ExpertiseTag, ProjectTag, LiveVotingSession, LiveVote, TeamMember,
|
||||
-- MentorAssignment, FilteringRule, FilteringResult, FilteringJob,
|
||||
-- AssignmentJob, TaggingJob, SpecialAward, AwardEligibility, AwardJuror,
|
||||
-- AwardVote, ReminderLog, ConflictOfInterest, EvaluationSummary,
|
||||
-- ProjectStatusHistory, MentorMessage, FileRequirement)
|
||||
-- -> All confirmed present in migrations.
|
||||
-- =============================================================================
|
||||
|
||||
-- =============================================================================
|
||||
-- SUMMARY OF CHANGES IN THIS MIGRATION:
|
||||
--
|
||||
-- NEW TABLE:
|
||||
-- - WizardTemplate (with programId FK, createdBy FK, indexes)
|
||||
--
|
||||
-- NEW COLUMNS:
|
||||
-- - SpecialAward.eligibilityJobStatus (TEXT, nullable)
|
||||
-- - SpecialAward.eligibilityJobTotal (INTEGER, nullable)
|
||||
-- - SpecialAward.eligibilityJobDone (INTEGER, nullable)
|
||||
-- - SpecialAward.eligibilityJobError (TEXT, nullable)
|
||||
-- - SpecialAward.eligibilityJobStarted (TIMESTAMP, nullable)
|
||||
--
|
||||
-- NEW INDEXES:
|
||||
-- - Assignment_projectId_userId_idx
|
||||
-- - AuditLog_sessionId_idx
|
||||
-- - ProjectFile_projectId_roundId_idx
|
||||
-- - MessageRecipient_userId_idx
|
||||
-- - MessageRecipient_messageId_userId_channel_key (UNIQUE)
|
||||
-- - AwardEligibility_awardId_eligible_idx
|
||||
-- - WizardTemplate_programId_idx
|
||||
-- - WizardTemplate_isGlobal_idx
|
||||
--
|
||||
-- NEW FOREIGN KEYS:
|
||||
-- - WizardTemplate_programId_fkey -> Program(id) ON DELETE CASCADE
|
||||
-- - WizardTemplate_createdBy_fkey -> User(id) ON DELETE RESTRICT
|
||||
-- =============================================================================
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
-- CreateIndex
|
||||
CREATE INDEX "AwardVote_awardId_userId_idx" ON "AwardVote"("awardId", "userId");
|
||||
-- CreateIndex
|
||||
CREATE INDEX "AwardVote_awardId_userId_idx" ON "AwardVote"("awardId", "userId");
|
||||
|
||||
@@ -1,99 +1,99 @@
|
||||
-- Migration: Add live voting enhancements (criteria voting, audience voting, AudienceVoter)
|
||||
-- Brings LiveVotingSession, LiveVote, and new AudienceVoter model in sync with schema.prisma
|
||||
-- Uses IF NOT EXISTS / DO $$ guards for idempotent execution
|
||||
|
||||
-- =============================================================================
|
||||
-- 1. LiveVotingSession: Add criteria-based & audience voting columns
|
||||
-- =============================================================================
|
||||
|
||||
ALTER TABLE "LiveVotingSession" ADD COLUMN IF NOT EXISTS "votingMode" TEXT NOT NULL DEFAULT 'simple';
|
||||
ALTER TABLE "LiveVotingSession" ADD COLUMN IF NOT EXISTS "criteriaJson" JSONB;
|
||||
ALTER TABLE "LiveVotingSession" ADD COLUMN IF NOT EXISTS "audienceVotingMode" TEXT NOT NULL DEFAULT 'disabled';
|
||||
ALTER TABLE "LiveVotingSession" ADD COLUMN IF NOT EXISTS "audienceMaxFavorites" INTEGER NOT NULL DEFAULT 3;
|
||||
ALTER TABLE "LiveVotingSession" ADD COLUMN IF NOT EXISTS "audienceRequireId" BOOLEAN NOT NULL DEFAULT false;
|
||||
ALTER TABLE "LiveVotingSession" ADD COLUMN IF NOT EXISTS "audienceVotingDuration" INTEGER;
|
||||
|
||||
-- =============================================================================
|
||||
-- 2. LiveVote: Add criteria scores, audience voter link, make userId nullable
|
||||
-- =============================================================================
|
||||
|
||||
ALTER TABLE "LiveVote" ADD COLUMN IF NOT EXISTS "criterionScoresJson" JSONB;
|
||||
ALTER TABLE "LiveVote" ADD COLUMN IF NOT EXISTS "audienceVoterId" TEXT;
|
||||
|
||||
-- Make userId nullable (was NOT NULL in init migration)
|
||||
ALTER TABLE "LiveVote" ALTER COLUMN "userId" DROP NOT NULL;
|
||||
|
||||
-- =============================================================================
|
||||
-- 3. AudienceVoter: New table for audience participation
|
||||
-- =============================================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "AudienceVoter" (
|
||||
"id" TEXT NOT NULL,
|
||||
"sessionId" TEXT NOT NULL,
|
||||
"token" TEXT NOT NULL,
|
||||
"identifier" TEXT,
|
||||
"identifierType" TEXT,
|
||||
"ipAddress" TEXT,
|
||||
"userAgent" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "AudienceVoter_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- Unique constraint on token
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "AudienceVoter" ADD CONSTRAINT "AudienceVoter_token_key" UNIQUE ("token");
|
||||
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||
|
||||
-- Indexes
|
||||
CREATE INDEX IF NOT EXISTS "AudienceVoter_sessionId_idx" ON "AudienceVoter"("sessionId");
|
||||
CREATE INDEX IF NOT EXISTS "AudienceVoter_token_idx" ON "AudienceVoter"("token");
|
||||
|
||||
-- Foreign key: AudienceVoter.sessionId -> LiveVotingSession.id
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "AudienceVoter" ADD CONSTRAINT "AudienceVoter_sessionId_fkey"
|
||||
FOREIGN KEY ("sessionId") REFERENCES "LiveVotingSession"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||
|
||||
-- =============================================================================
|
||||
-- 4. LiveVote: Foreign key and indexes for audienceVoterId
|
||||
-- =============================================================================
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "LiveVote_audienceVoterId_idx" ON "LiveVote"("audienceVoterId");
|
||||
|
||||
-- Foreign key: LiveVote.audienceVoterId -> AudienceVoter.id
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "LiveVote" ADD CONSTRAINT "LiveVote_audienceVoterId_fkey"
|
||||
FOREIGN KEY ("audienceVoterId") REFERENCES "AudienceVoter"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||
|
||||
-- Unique constraint: sessionId + projectId + audienceVoterId
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "LiveVote" ADD CONSTRAINT "LiveVote_sessionId_projectId_audienceVoterId_key"
|
||||
UNIQUE ("sessionId", "projectId", "audienceVoterId");
|
||||
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||
|
||||
-- =============================================================================
|
||||
-- SUMMARY:
|
||||
--
|
||||
-- LiveVotingSession new columns:
|
||||
-- - votingMode (TEXT, default 'simple')
|
||||
-- - criteriaJson (JSONB, nullable)
|
||||
-- - audienceVotingMode (TEXT, default 'disabled')
|
||||
-- - audienceMaxFavorites (INTEGER, default 3)
|
||||
-- - audienceRequireId (BOOLEAN, default false)
|
||||
-- - audienceVotingDuration (INTEGER, nullable)
|
||||
--
|
||||
-- LiveVote changes:
|
||||
-- - criterionScoresJson (JSONB, nullable) - new column
|
||||
-- - audienceVoterId (TEXT, nullable) - new column
|
||||
-- - userId changed from NOT NULL to nullable
|
||||
-- - New unique: (sessionId, projectId, audienceVoterId)
|
||||
-- - New index: audienceVoterId
|
||||
-- - New FK: audienceVoterId -> AudienceVoter(id)
|
||||
--
|
||||
-- New table: AudienceVoter
|
||||
-- - id, sessionId, token (unique), identifier, identifierType,
|
||||
-- ipAddress, userAgent, createdAt
|
||||
-- - FK: sessionId -> LiveVotingSession(id) CASCADE
|
||||
-- =============================================================================
|
||||
-- Migration: Add live voting enhancements (criteria voting, audience voting, AudienceVoter)
|
||||
-- Brings LiveVotingSession, LiveVote, and new AudienceVoter model in sync with schema.prisma
|
||||
-- Uses IF NOT EXISTS / DO $$ guards for idempotent execution
|
||||
|
||||
-- =============================================================================
|
||||
-- 1. LiveVotingSession: Add criteria-based & audience voting columns
|
||||
-- =============================================================================
|
||||
|
||||
ALTER TABLE "LiveVotingSession" ADD COLUMN IF NOT EXISTS "votingMode" TEXT NOT NULL DEFAULT 'simple';
|
||||
ALTER TABLE "LiveVotingSession" ADD COLUMN IF NOT EXISTS "criteriaJson" JSONB;
|
||||
ALTER TABLE "LiveVotingSession" ADD COLUMN IF NOT EXISTS "audienceVotingMode" TEXT NOT NULL DEFAULT 'disabled';
|
||||
ALTER TABLE "LiveVotingSession" ADD COLUMN IF NOT EXISTS "audienceMaxFavorites" INTEGER NOT NULL DEFAULT 3;
|
||||
ALTER TABLE "LiveVotingSession" ADD COLUMN IF NOT EXISTS "audienceRequireId" BOOLEAN NOT NULL DEFAULT false;
|
||||
ALTER TABLE "LiveVotingSession" ADD COLUMN IF NOT EXISTS "audienceVotingDuration" INTEGER;
|
||||
|
||||
-- =============================================================================
|
||||
-- 2. LiveVote: Add criteria scores, audience voter link, make userId nullable
|
||||
-- =============================================================================
|
||||
|
||||
ALTER TABLE "LiveVote" ADD COLUMN IF NOT EXISTS "criterionScoresJson" JSONB;
|
||||
ALTER TABLE "LiveVote" ADD COLUMN IF NOT EXISTS "audienceVoterId" TEXT;
|
||||
|
||||
-- Make userId nullable (was NOT NULL in init migration)
|
||||
ALTER TABLE "LiveVote" ALTER COLUMN "userId" DROP NOT NULL;
|
||||
|
||||
-- =============================================================================
|
||||
-- 3. AudienceVoter: New table for audience participation
|
||||
-- =============================================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "AudienceVoter" (
|
||||
"id" TEXT NOT NULL,
|
||||
"sessionId" TEXT NOT NULL,
|
||||
"token" TEXT NOT NULL,
|
||||
"identifier" TEXT,
|
||||
"identifierType" TEXT,
|
||||
"ipAddress" TEXT,
|
||||
"userAgent" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "AudienceVoter_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- Unique constraint on token
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "AudienceVoter" ADD CONSTRAINT "AudienceVoter_token_key" UNIQUE ("token");
|
||||
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||
|
||||
-- Indexes
|
||||
CREATE INDEX IF NOT EXISTS "AudienceVoter_sessionId_idx" ON "AudienceVoter"("sessionId");
|
||||
CREATE INDEX IF NOT EXISTS "AudienceVoter_token_idx" ON "AudienceVoter"("token");
|
||||
|
||||
-- Foreign key: AudienceVoter.sessionId -> LiveVotingSession.id
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "AudienceVoter" ADD CONSTRAINT "AudienceVoter_sessionId_fkey"
|
||||
FOREIGN KEY ("sessionId") REFERENCES "LiveVotingSession"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||
|
||||
-- =============================================================================
|
||||
-- 4. LiveVote: Foreign key and indexes for audienceVoterId
|
||||
-- =============================================================================
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "LiveVote_audienceVoterId_idx" ON "LiveVote"("audienceVoterId");
|
||||
|
||||
-- Foreign key: LiveVote.audienceVoterId -> AudienceVoter.id
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "LiveVote" ADD CONSTRAINT "LiveVote_audienceVoterId_fkey"
|
||||
FOREIGN KEY ("audienceVoterId") REFERENCES "AudienceVoter"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||
|
||||
-- Unique constraint: sessionId + projectId + audienceVoterId
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "LiveVote" ADD CONSTRAINT "LiveVote_sessionId_projectId_audienceVoterId_key"
|
||||
UNIQUE ("sessionId", "projectId", "audienceVoterId");
|
||||
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||
|
||||
-- =============================================================================
|
||||
-- SUMMARY:
|
||||
--
|
||||
-- LiveVotingSession new columns:
|
||||
-- - votingMode (TEXT, default 'simple')
|
||||
-- - criteriaJson (JSONB, nullable)
|
||||
-- - audienceVotingMode (TEXT, default 'disabled')
|
||||
-- - audienceMaxFavorites (INTEGER, default 3)
|
||||
-- - audienceRequireId (BOOLEAN, default false)
|
||||
-- - audienceVotingDuration (INTEGER, nullable)
|
||||
--
|
||||
-- LiveVote changes:
|
||||
-- - criterionScoresJson (JSONB, nullable) - new column
|
||||
-- - audienceVoterId (TEXT, nullable) - new column
|
||||
-- - userId changed from NOT NULL to nullable
|
||||
-- - New unique: (sessionId, projectId, audienceVoterId)
|
||||
-- - New index: audienceVoterId
|
||||
-- - New FK: audienceVoterId -> AudienceVoter(id)
|
||||
--
|
||||
-- New table: AudienceVoter
|
||||
-- - id, sessionId, token (unique), identifier, identifierType,
|
||||
-- ipAddress, userAgent, createdAt
|
||||
-- - FK: sessionId -> LiveVotingSession(id) CASCADE
|
||||
-- =============================================================================
|
||||
|
||||
@@ -0,0 +1,572 @@
|
||||
-- =============================================================================
|
||||
-- Phase 0+1: Add Competition/Round Architecture (additive — no breaking changes)
|
||||
-- =============================================================================
|
||||
-- New enums, new tables, new optional columns on existing tables.
|
||||
-- Old Pipeline/Track/Stage tables are untouched.
|
||||
|
||||
-- ─── New Enum Types ──────────────────────────────────────────────────────────
|
||||
|
||||
CREATE TYPE "CompetitionStatus" AS ENUM ('DRAFT', 'ACTIVE', 'CLOSED', 'ARCHIVED');
|
||||
CREATE TYPE "RoundType" AS ENUM ('INTAKE', 'FILTERING', 'EVALUATION', 'SUBMISSION', 'MENTORING', 'LIVE_FINAL', 'DELIBERATION');
|
||||
CREATE TYPE "RoundStatus" AS ENUM ('ROUND_DRAFT', 'ROUND_ACTIVE', 'ROUND_CLOSED', 'ROUND_ARCHIVED');
|
||||
CREATE TYPE "ProjectRoundStateValue" AS ENUM ('PENDING', 'IN_PROGRESS', 'PASSED', 'REJECTED', 'COMPLETED', 'WITHDRAWN');
|
||||
CREATE TYPE "AdvancementRuleType" AS ENUM ('AUTO_ADVANCE', 'SCORE_THRESHOLD', 'TOP_N', 'ADMIN_SELECTION', 'AI_RECOMMENDED');
|
||||
CREATE TYPE "CapMode" AS ENUM ('HARD', 'SOFT', 'NONE');
|
||||
CREATE TYPE "DeadlinePolicy" AS ENUM ('HARD_DEADLINE', 'FLAG', 'GRACE');
|
||||
CREATE TYPE "JuryGroupMemberRole" AS ENUM ('CHAIR', 'MEMBER', 'OBSERVER');
|
||||
CREATE TYPE "AssignmentIntentSource" AS ENUM ('INVITE', 'ADMIN', 'SYSTEM');
|
||||
CREATE TYPE "AssignmentIntentStatus" AS ENUM ('INTENT_PENDING', 'HONORED', 'OVERRIDDEN', 'EXPIRED', 'CANCELLED');
|
||||
CREATE TYPE "MentorMessageRole" AS ENUM ('MENTOR_ROLE', 'APPLICANT_ROLE', 'ADMIN_ROLE');
|
||||
CREATE TYPE "SubmissionPromotionSource" AS ENUM ('MENTOR_FILE', 'ADMIN_REPLACEMENT');
|
||||
CREATE TYPE "DeliberationMode" AS ENUM ('SINGLE_WINNER_VOTE', 'FULL_RANKING');
|
||||
CREATE TYPE "DeliberationStatus" AS ENUM ('DELIB_OPEN', 'VOTING', 'TALLYING', 'RUNOFF', 'DELIB_LOCKED');
|
||||
CREATE TYPE "TieBreakMethod" AS ENUM ('TIE_RUNOFF', 'TIE_ADMIN_DECIDES', 'SCORE_FALLBACK');
|
||||
CREATE TYPE "DeliberationParticipantStatus" AS ENUM ('REQUIRED', 'ABSENT_EXCUSED', 'REPLACED', 'REPLACEMENT_ACTIVE');
|
||||
CREATE TYPE "AwardEligibilityMode" AS ENUM ('SEPARATE_POOL', 'STAY_IN_MAIN');
|
||||
|
||||
-- Add FEATURE_FLAGS to SettingCategory enum
|
||||
ALTER TYPE "SettingCategory" ADD VALUE 'FEATURE_FLAGS';
|
||||
|
||||
-- ─── New Tables ──────────────────────────────────────────────────────────────
|
||||
|
||||
-- Competition (replaces Pipeline)
|
||||
CREATE TABLE "Competition" (
|
||||
"id" TEXT NOT NULL,
|
||||
"programId" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"slug" TEXT NOT NULL,
|
||||
"status" "CompetitionStatus" NOT NULL DEFAULT 'DRAFT',
|
||||
"categoryMode" TEXT NOT NULL DEFAULT 'SHARED',
|
||||
"startupFinalistCount" INTEGER NOT NULL DEFAULT 3,
|
||||
"conceptFinalistCount" INTEGER NOT NULL DEFAULT 3,
|
||||
"notifyOnRoundAdvance" BOOLEAN NOT NULL DEFAULT true,
|
||||
"notifyOnDeadlineApproach" BOOLEAN NOT NULL DEFAULT true,
|
||||
"deadlineReminderDays" INTEGER[] DEFAULT ARRAY[7, 3, 1]::INTEGER[],
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Competition_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- Round (replaces Stage)
|
||||
CREATE TABLE "Round" (
|
||||
"id" TEXT NOT NULL,
|
||||
"competitionId" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"slug" TEXT NOT NULL,
|
||||
"roundType" "RoundType" NOT NULL,
|
||||
"status" "RoundStatus" NOT NULL DEFAULT 'ROUND_DRAFT',
|
||||
"sortOrder" INTEGER NOT NULL DEFAULT 0,
|
||||
"windowOpenAt" TIMESTAMP(3),
|
||||
"windowCloseAt" TIMESTAMP(3),
|
||||
"configJson" JSONB,
|
||||
"purposeKey" TEXT,
|
||||
"juryGroupId" TEXT,
|
||||
"submissionWindowId" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Round_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- ProjectRoundState
|
||||
CREATE TABLE "ProjectRoundState" (
|
||||
"id" TEXT NOT NULL,
|
||||
"projectId" TEXT NOT NULL,
|
||||
"roundId" TEXT NOT NULL,
|
||||
"state" "ProjectRoundStateValue" NOT NULL DEFAULT 'PENDING',
|
||||
"enteredAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"exitedAt" TIMESTAMP(3),
|
||||
"metadataJson" JSONB,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "ProjectRoundState_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- AdvancementRule
|
||||
CREATE TABLE "AdvancementRule" (
|
||||
"id" TEXT NOT NULL,
|
||||
"roundId" TEXT NOT NULL,
|
||||
"targetRoundId" TEXT,
|
||||
"ruleType" "AdvancementRuleType" NOT NULL,
|
||||
"configJson" JSONB NOT NULL,
|
||||
"isDefault" BOOLEAN NOT NULL DEFAULT true,
|
||||
"sortOrder" INTEGER NOT NULL DEFAULT 0,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "AdvancementRule_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- JuryGroup
|
||||
CREATE TABLE "JuryGroup" (
|
||||
"id" TEXT NOT NULL,
|
||||
"competitionId" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"slug" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"sortOrder" INTEGER NOT NULL DEFAULT 0,
|
||||
"defaultMaxAssignments" INTEGER NOT NULL DEFAULT 20,
|
||||
"defaultCapMode" "CapMode" NOT NULL DEFAULT 'SOFT',
|
||||
"softCapBuffer" INTEGER NOT NULL DEFAULT 2,
|
||||
"categoryQuotasEnabled" BOOLEAN NOT NULL DEFAULT false,
|
||||
"defaultCategoryQuotas" JSONB,
|
||||
"allowJurorCapAdjustment" BOOLEAN NOT NULL DEFAULT false,
|
||||
"allowJurorRatioAdjustment" BOOLEAN NOT NULL DEFAULT false,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "JuryGroup_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- JuryGroupMember
|
||||
CREATE TABLE "JuryGroupMember" (
|
||||
"id" TEXT NOT NULL,
|
||||
"juryGroupId" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"role" "JuryGroupMemberRole" NOT NULL DEFAULT 'MEMBER',
|
||||
"joinedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"maxAssignmentsOverride" INTEGER,
|
||||
"capModeOverride" "CapMode",
|
||||
"categoryQuotasOverride" JSONB,
|
||||
"preferredStartupRatio" DOUBLE PRECISION,
|
||||
"availabilityNotes" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "JuryGroupMember_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- SubmissionWindow
|
||||
CREATE TABLE "SubmissionWindow" (
|
||||
"id" TEXT NOT NULL,
|
||||
"competitionId" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"slug" TEXT NOT NULL,
|
||||
"roundNumber" INTEGER NOT NULL,
|
||||
"sortOrder" INTEGER NOT NULL DEFAULT 0,
|
||||
"windowOpenAt" TIMESTAMP(3),
|
||||
"windowCloseAt" TIMESTAMP(3),
|
||||
"deadlinePolicy" "DeadlinePolicy" NOT NULL DEFAULT 'FLAG',
|
||||
"graceHours" INTEGER,
|
||||
"lockOnClose" BOOLEAN NOT NULL DEFAULT true,
|
||||
"isLocked" BOOLEAN NOT NULL DEFAULT false,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "SubmissionWindow_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- SubmissionFileRequirement
|
||||
CREATE TABLE "SubmissionFileRequirement" (
|
||||
"id" TEXT NOT NULL,
|
||||
"submissionWindowId" TEXT NOT NULL,
|
||||
"label" TEXT NOT NULL,
|
||||
"slug" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"mimeTypes" TEXT[],
|
||||
"maxSizeMb" INTEGER,
|
||||
"required" BOOLEAN NOT NULL DEFAULT true,
|
||||
"sortOrder" INTEGER NOT NULL DEFAULT 0,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "SubmissionFileRequirement_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- RoundSubmissionVisibility
|
||||
CREATE TABLE "RoundSubmissionVisibility" (
|
||||
"id" TEXT NOT NULL,
|
||||
"roundId" TEXT NOT NULL,
|
||||
"submissionWindowId" TEXT NOT NULL,
|
||||
"canView" BOOLEAN NOT NULL DEFAULT true,
|
||||
"displayLabel" TEXT,
|
||||
|
||||
CONSTRAINT "RoundSubmissionVisibility_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- AssignmentIntent
|
||||
CREATE TABLE "AssignmentIntent" (
|
||||
"id" TEXT NOT NULL,
|
||||
"juryGroupMemberId" TEXT NOT NULL,
|
||||
"roundId" TEXT NOT NULL,
|
||||
"projectId" TEXT NOT NULL,
|
||||
"source" "AssignmentIntentSource" NOT NULL,
|
||||
"status" "AssignmentIntentStatus" NOT NULL DEFAULT 'INTENT_PENDING',
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "AssignmentIntent_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- AssignmentException
|
||||
CREATE TABLE "AssignmentException" (
|
||||
"id" TEXT NOT NULL,
|
||||
"assignmentId" TEXT NOT NULL,
|
||||
"reason" TEXT NOT NULL,
|
||||
"overCapBy" INTEGER NOT NULL,
|
||||
"approvedById" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "AssignmentException_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- MentorFile
|
||||
CREATE TABLE "MentorFile" (
|
||||
"id" TEXT NOT NULL,
|
||||
"mentorAssignmentId" TEXT NOT NULL,
|
||||
"uploadedByUserId" TEXT NOT NULL,
|
||||
"fileName" TEXT NOT NULL,
|
||||
"mimeType" TEXT NOT NULL,
|
||||
"size" INTEGER NOT NULL,
|
||||
"bucket" TEXT NOT NULL,
|
||||
"objectKey" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"isPromoted" BOOLEAN NOT NULL DEFAULT false,
|
||||
"promotedToFileId" TEXT,
|
||||
"promotedAt" TIMESTAMP(3),
|
||||
"promotedByUserId" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "MentorFile_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- MentorFileComment
|
||||
CREATE TABLE "MentorFileComment" (
|
||||
"id" TEXT NOT NULL,
|
||||
"mentorFileId" TEXT NOT NULL,
|
||||
"authorId" TEXT NOT NULL,
|
||||
"content" TEXT NOT NULL,
|
||||
"parentCommentId" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "MentorFileComment_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- SubmissionPromotionEvent
|
||||
CREATE TABLE "SubmissionPromotionEvent" (
|
||||
"id" TEXT NOT NULL,
|
||||
"projectId" TEXT NOT NULL,
|
||||
"roundId" TEXT NOT NULL,
|
||||
"slotKey" TEXT NOT NULL,
|
||||
"sourceType" "SubmissionPromotionSource" NOT NULL,
|
||||
"sourceFileId" TEXT,
|
||||
"promotedById" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "SubmissionPromotionEvent_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- DeliberationSession
|
||||
CREATE TABLE "DeliberationSession" (
|
||||
"id" TEXT NOT NULL,
|
||||
"competitionId" TEXT NOT NULL,
|
||||
"roundId" TEXT NOT NULL,
|
||||
"category" "CompetitionCategory" NOT NULL,
|
||||
"mode" "DeliberationMode" NOT NULL,
|
||||
"showCollectiveRankings" BOOLEAN NOT NULL DEFAULT false,
|
||||
"showPriorJuryData" BOOLEAN NOT NULL DEFAULT false,
|
||||
"status" "DeliberationStatus" NOT NULL,
|
||||
"tieBreakMethod" "TieBreakMethod" NOT NULL,
|
||||
"adminOverrideResult" JSONB,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "DeliberationSession_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- DeliberationVote
|
||||
CREATE TABLE "DeliberationVote" (
|
||||
"id" TEXT NOT NULL,
|
||||
"sessionId" TEXT NOT NULL,
|
||||
"juryMemberId" TEXT NOT NULL,
|
||||
"projectId" TEXT NOT NULL,
|
||||
"rank" INTEGER,
|
||||
"isWinnerPick" BOOLEAN NOT NULL DEFAULT false,
|
||||
"runoffRound" INTEGER NOT NULL DEFAULT 0,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "DeliberationVote_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- DeliberationResult
|
||||
CREATE TABLE "DeliberationResult" (
|
||||
"id" TEXT NOT NULL,
|
||||
"sessionId" TEXT NOT NULL,
|
||||
"projectId" TEXT NOT NULL,
|
||||
"finalRank" INTEGER NOT NULL,
|
||||
"voteCount" INTEGER NOT NULL DEFAULT 0,
|
||||
"isAdminOverridden" BOOLEAN NOT NULL DEFAULT false,
|
||||
"overrideReason" TEXT,
|
||||
|
||||
CONSTRAINT "DeliberationResult_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- DeliberationParticipant
|
||||
CREATE TABLE "DeliberationParticipant" (
|
||||
"id" TEXT NOT NULL,
|
||||
"sessionId" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"status" "DeliberationParticipantStatus" NOT NULL,
|
||||
"replacedById" TEXT,
|
||||
|
||||
CONSTRAINT "DeliberationParticipant_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- ResultLock
|
||||
CREATE TABLE "ResultLock" (
|
||||
"id" TEXT NOT NULL,
|
||||
"competitionId" TEXT NOT NULL,
|
||||
"roundId" TEXT NOT NULL,
|
||||
"category" "CompetitionCategory" NOT NULL,
|
||||
"lockedById" TEXT NOT NULL,
|
||||
"resultSnapshot" JSONB NOT NULL,
|
||||
"lockedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "ResultLock_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- ResultUnlockEvent
|
||||
CREATE TABLE "ResultUnlockEvent" (
|
||||
"id" TEXT NOT NULL,
|
||||
"resultLockId" TEXT NOT NULL,
|
||||
"unlockedById" TEXT NOT NULL,
|
||||
"reason" TEXT NOT NULL,
|
||||
"unlockedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "ResultUnlockEvent_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- ─── Add Columns to Existing Tables ──────────────────────────────────────────
|
||||
|
||||
-- Assignment: add juryGroupId
|
||||
ALTER TABLE "Assignment" ADD COLUMN "juryGroupId" TEXT;
|
||||
|
||||
-- SpecialAward: add competition/round architecture fields
|
||||
ALTER TABLE "SpecialAward" ADD COLUMN "competitionId" TEXT;
|
||||
ALTER TABLE "SpecialAward" ADD COLUMN "evaluationRoundId" TEXT;
|
||||
ALTER TABLE "SpecialAward" ADD COLUMN "juryGroupId" TEXT;
|
||||
ALTER TABLE "SpecialAward" ADD COLUMN "eligibilityMode" "AwardEligibilityMode" NOT NULL DEFAULT 'STAY_IN_MAIN';
|
||||
ALTER TABLE "SpecialAward" ADD COLUMN "decisionMode" TEXT;
|
||||
|
||||
-- MentorAssignment: add workspace fields
|
||||
ALTER TABLE "MentorAssignment" ADD COLUMN "workspaceEnabled" BOOLEAN NOT NULL DEFAULT false;
|
||||
ALTER TABLE "MentorAssignment" ADD COLUMN "workspaceOpenAt" TIMESTAMP(3);
|
||||
ALTER TABLE "MentorAssignment" ADD COLUMN "workspaceCloseAt" TIMESTAMP(3);
|
||||
|
||||
-- MentorMessage: add workspace fields
|
||||
ALTER TABLE "MentorMessage" ADD COLUMN "workspaceId" TEXT;
|
||||
ALTER TABLE "MentorMessage" ADD COLUMN "senderRole" "MentorMessageRole";
|
||||
|
||||
-- ProjectFile: add submission window link
|
||||
ALTER TABLE "ProjectFile" ADD COLUMN "submissionWindowId" TEXT;
|
||||
ALTER TABLE "ProjectFile" ADD COLUMN "submissionFileRequirementId" TEXT;
|
||||
|
||||
-- ─── Unique Constraints ──────────────────────────────────────────────────────
|
||||
|
||||
CREATE UNIQUE INDEX "Competition_slug_key" ON "Competition"("slug");
|
||||
CREATE UNIQUE INDEX "Round_competitionId_slug_key" ON "Round"("competitionId", "slug");
|
||||
CREATE UNIQUE INDEX "Round_competitionId_sortOrder_key" ON "Round"("competitionId", "sortOrder");
|
||||
CREATE UNIQUE INDEX "ProjectRoundState_projectId_roundId_key" ON "ProjectRoundState"("projectId", "roundId");
|
||||
CREATE UNIQUE INDEX "JuryGroup_competitionId_slug_key" ON "JuryGroup"("competitionId", "slug");
|
||||
CREATE UNIQUE INDEX "JuryGroupMember_juryGroupId_userId_key" ON "JuryGroupMember"("juryGroupId", "userId");
|
||||
CREATE UNIQUE INDEX "SubmissionWindow_competitionId_slug_key" ON "SubmissionWindow"("competitionId", "slug");
|
||||
CREATE UNIQUE INDEX "SubmissionWindow_competitionId_roundNumber_key" ON "SubmissionWindow"("competitionId", "roundNumber");
|
||||
CREATE UNIQUE INDEX "RoundSubmissionVisibility_roundId_submissionWindowId_key" ON "RoundSubmissionVisibility"("roundId", "submissionWindowId");
|
||||
CREATE UNIQUE INDEX "AssignmentIntent_juryGroupMemberId_roundId_projectId_key" ON "AssignmentIntent"("juryGroupMemberId", "roundId", "projectId");
|
||||
CREATE UNIQUE INDEX "MentorFile_promotedToFileId_key" ON "MentorFile"("promotedToFileId");
|
||||
CREATE UNIQUE INDEX "DeliberationVote_sessionId_juryMemberId_projectId_runoffRo_key" ON "DeliberationVote"("sessionId", "juryMemberId", "projectId", "runoffRound");
|
||||
CREATE UNIQUE INDEX "DeliberationResult_sessionId_projectId_key" ON "DeliberationResult"("sessionId", "projectId");
|
||||
CREATE UNIQUE INDEX "DeliberationParticipant_sessionId_userId_key" ON "DeliberationParticipant"("sessionId", "userId");
|
||||
CREATE UNIQUE INDEX "SubmissionFileRequirement_submissionWindowId_slug_key" ON "SubmissionFileRequirement"("submissionWindowId", "slug");
|
||||
CREATE UNIQUE INDEX "AdvancementRule_roundId_sortOrder_key" ON "AdvancementRule"("roundId", "sortOrder");
|
||||
|
||||
-- ─── Indexes ─────────────────────────────────────────────────────────────────
|
||||
|
||||
-- Competition
|
||||
CREATE INDEX "Competition_programId_idx" ON "Competition"("programId");
|
||||
CREATE INDEX "Competition_status_idx" ON "Competition"("status");
|
||||
|
||||
-- Round
|
||||
CREATE INDEX "Round_competitionId_idx" ON "Round"("competitionId");
|
||||
CREATE INDEX "Round_roundType_idx" ON "Round"("roundType");
|
||||
CREATE INDEX "Round_status_idx" ON "Round"("status");
|
||||
|
||||
-- ProjectRoundState
|
||||
CREATE INDEX "ProjectRoundState_projectId_idx" ON "ProjectRoundState"("projectId");
|
||||
CREATE INDEX "ProjectRoundState_roundId_idx" ON "ProjectRoundState"("roundId");
|
||||
CREATE INDEX "ProjectRoundState_state_idx" ON "ProjectRoundState"("state");
|
||||
|
||||
-- AdvancementRule
|
||||
CREATE INDEX "AdvancementRule_roundId_idx" ON "AdvancementRule"("roundId");
|
||||
|
||||
-- JuryGroup
|
||||
CREATE INDEX "JuryGroup_competitionId_idx" ON "JuryGroup"("competitionId");
|
||||
|
||||
-- JuryGroupMember
|
||||
CREATE INDEX "JuryGroupMember_juryGroupId_idx" ON "JuryGroupMember"("juryGroupId");
|
||||
CREATE INDEX "JuryGroupMember_userId_idx" ON "JuryGroupMember"("userId");
|
||||
|
||||
-- SubmissionWindow
|
||||
CREATE INDEX "SubmissionWindow_competitionId_idx" ON "SubmissionWindow"("competitionId");
|
||||
|
||||
-- SubmissionFileRequirement
|
||||
CREATE INDEX "SubmissionFileRequirement_submissionWindowId_idx" ON "SubmissionFileRequirement"("submissionWindowId");
|
||||
|
||||
-- RoundSubmissionVisibility
|
||||
CREATE INDEX "RoundSubmissionVisibility_roundId_idx" ON "RoundSubmissionVisibility"("roundId");
|
||||
|
||||
-- AssignmentIntent
|
||||
CREATE INDEX "AssignmentIntent_roundId_idx" ON "AssignmentIntent"("roundId");
|
||||
CREATE INDEX "AssignmentIntent_projectId_idx" ON "AssignmentIntent"("projectId");
|
||||
CREATE INDEX "AssignmentIntent_status_idx" ON "AssignmentIntent"("status");
|
||||
|
||||
-- AssignmentException
|
||||
CREATE INDEX "AssignmentException_assignmentId_idx" ON "AssignmentException"("assignmentId");
|
||||
CREATE INDEX "AssignmentException_approvedById_idx" ON "AssignmentException"("approvedById");
|
||||
|
||||
-- MentorFile
|
||||
CREATE INDEX "MentorFile_mentorAssignmentId_idx" ON "MentorFile"("mentorAssignmentId");
|
||||
CREATE INDEX "MentorFile_uploadedByUserId_idx" ON "MentorFile"("uploadedByUserId");
|
||||
|
||||
-- MentorFileComment
|
||||
CREATE INDEX "MentorFileComment_mentorFileId_idx" ON "MentorFileComment"("mentorFileId");
|
||||
CREATE INDEX "MentorFileComment_authorId_idx" ON "MentorFileComment"("authorId");
|
||||
CREATE INDEX "MentorFileComment_parentCommentId_idx" ON "MentorFileComment"("parentCommentId");
|
||||
|
||||
-- SubmissionPromotionEvent
|
||||
CREATE INDEX "SubmissionPromotionEvent_projectId_idx" ON "SubmissionPromotionEvent"("projectId");
|
||||
CREATE INDEX "SubmissionPromotionEvent_roundId_idx" ON "SubmissionPromotionEvent"("roundId");
|
||||
CREATE INDEX "SubmissionPromotionEvent_sourceFileId_idx" ON "SubmissionPromotionEvent"("sourceFileId");
|
||||
|
||||
-- DeliberationSession
|
||||
CREATE INDEX "DeliberationSession_competitionId_idx" ON "DeliberationSession"("competitionId");
|
||||
CREATE INDEX "DeliberationSession_roundId_idx" ON "DeliberationSession"("roundId");
|
||||
CREATE INDEX "DeliberationSession_status_idx" ON "DeliberationSession"("status");
|
||||
|
||||
-- DeliberationVote
|
||||
CREATE INDEX "DeliberationVote_sessionId_idx" ON "DeliberationVote"("sessionId");
|
||||
CREATE INDEX "DeliberationVote_juryMemberId_idx" ON "DeliberationVote"("juryMemberId");
|
||||
CREATE INDEX "DeliberationVote_projectId_idx" ON "DeliberationVote"("projectId");
|
||||
|
||||
-- DeliberationResult
|
||||
CREATE INDEX "DeliberationResult_sessionId_idx" ON "DeliberationResult"("sessionId");
|
||||
CREATE INDEX "DeliberationResult_projectId_idx" ON "DeliberationResult"("projectId");
|
||||
|
||||
-- DeliberationParticipant
|
||||
CREATE INDEX "DeliberationParticipant_sessionId_idx" ON "DeliberationParticipant"("sessionId");
|
||||
CREATE INDEX "DeliberationParticipant_userId_idx" ON "DeliberationParticipant"("userId");
|
||||
|
||||
-- ResultLock
|
||||
CREATE INDEX "ResultLock_competitionId_idx" ON "ResultLock"("competitionId");
|
||||
CREATE INDEX "ResultLock_roundId_idx" ON "ResultLock"("roundId");
|
||||
CREATE INDEX "ResultLock_category_idx" ON "ResultLock"("category");
|
||||
|
||||
-- ResultUnlockEvent
|
||||
CREATE INDEX "ResultUnlockEvent_resultLockId_idx" ON "ResultUnlockEvent"("resultLockId");
|
||||
CREATE INDEX "ResultUnlockEvent_unlockedById_idx" ON "ResultUnlockEvent"("unlockedById");
|
||||
|
||||
-- Indexes on modified existing tables
|
||||
CREATE INDEX "Assignment_juryGroupId_idx" ON "Assignment"("juryGroupId");
|
||||
CREATE INDEX "SpecialAward_competitionId_idx" ON "SpecialAward"("competitionId");
|
||||
CREATE INDEX "SpecialAward_evaluationRoundId_idx" ON "SpecialAward"("evaluationRoundId");
|
||||
CREATE INDEX "MentorMessage_workspaceId_idx" ON "MentorMessage"("workspaceId");
|
||||
CREATE INDEX "ProjectFile_submissionWindowId_idx" ON "ProjectFile"("submissionWindowId");
|
||||
CREATE INDEX "ProjectFile_submissionFileRequirementId_idx" ON "ProjectFile"("submissionFileRequirementId");
|
||||
|
||||
-- ─── Foreign Keys ────────────────────────────────────────────────────────────
|
||||
|
||||
-- Competition
|
||||
ALTER TABLE "Competition" ADD CONSTRAINT "Competition_programId_fkey" FOREIGN KEY ("programId") REFERENCES "Program"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- Round
|
||||
ALTER TABLE "Round" ADD CONSTRAINT "Round_competitionId_fkey" FOREIGN KEY ("competitionId") REFERENCES "Competition"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "Round" ADD CONSTRAINT "Round_juryGroupId_fkey" FOREIGN KEY ("juryGroupId") REFERENCES "JuryGroup"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
ALTER TABLE "Round" ADD CONSTRAINT "Round_submissionWindowId_fkey" FOREIGN KEY ("submissionWindowId") REFERENCES "SubmissionWindow"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- ProjectRoundState
|
||||
ALTER TABLE "ProjectRoundState" ADD CONSTRAINT "ProjectRoundState_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "ProjectRoundState" ADD CONSTRAINT "ProjectRoundState_roundId_fkey" FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AdvancementRule
|
||||
ALTER TABLE "AdvancementRule" ADD CONSTRAINT "AdvancementRule_roundId_fkey" FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- JuryGroup
|
||||
ALTER TABLE "JuryGroup" ADD CONSTRAINT "JuryGroup_competitionId_fkey" FOREIGN KEY ("competitionId") REFERENCES "Competition"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- JuryGroupMember
|
||||
ALTER TABLE "JuryGroupMember" ADD CONSTRAINT "JuryGroupMember_juryGroupId_fkey" FOREIGN KEY ("juryGroupId") REFERENCES "JuryGroup"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "JuryGroupMember" ADD CONSTRAINT "JuryGroupMember_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- SubmissionWindow
|
||||
ALTER TABLE "SubmissionWindow" ADD CONSTRAINT "SubmissionWindow_competitionId_fkey" FOREIGN KEY ("competitionId") REFERENCES "Competition"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- SubmissionFileRequirement
|
||||
ALTER TABLE "SubmissionFileRequirement" ADD CONSTRAINT "SubmissionFileRequirement_submissionWindowId_fkey" FOREIGN KEY ("submissionWindowId") REFERENCES "SubmissionWindow"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- RoundSubmissionVisibility
|
||||
ALTER TABLE "RoundSubmissionVisibility" ADD CONSTRAINT "RoundSubmissionVisibility_roundId_fkey" FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "RoundSubmissionVisibility" ADD CONSTRAINT "RoundSubmissionVisibility_submissionWindowId_fkey" FOREIGN KEY ("submissionWindowId") REFERENCES "SubmissionWindow"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AssignmentIntent
|
||||
ALTER TABLE "AssignmentIntent" ADD CONSTRAINT "AssignmentIntent_juryGroupMemberId_fkey" FOREIGN KEY ("juryGroupMemberId") REFERENCES "JuryGroupMember"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "AssignmentIntent" ADD CONSTRAINT "AssignmentIntent_roundId_fkey" FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "AssignmentIntent" ADD CONSTRAINT "AssignmentIntent_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AssignmentException
|
||||
ALTER TABLE "AssignmentException" ADD CONSTRAINT "AssignmentException_assignmentId_fkey" FOREIGN KEY ("assignmentId") REFERENCES "Assignment"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "AssignmentException" ADD CONSTRAINT "AssignmentException_approvedById_fkey" FOREIGN KEY ("approvedById") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- MentorFile
|
||||
ALTER TABLE "MentorFile" ADD CONSTRAINT "MentorFile_mentorAssignmentId_fkey" FOREIGN KEY ("mentorAssignmentId") REFERENCES "MentorAssignment"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "MentorFile" ADD CONSTRAINT "MentorFile_uploadedByUserId_fkey" FOREIGN KEY ("uploadedByUserId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE "MentorFile" ADD CONSTRAINT "MentorFile_promotedByUserId_fkey" FOREIGN KEY ("promotedByUserId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
ALTER TABLE "MentorFile" ADD CONSTRAINT "MentorFile_promotedToFileId_fkey" FOREIGN KEY ("promotedToFileId") REFERENCES "ProjectFile"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- MentorFileComment
|
||||
ALTER TABLE "MentorFileComment" ADD CONSTRAINT "MentorFileComment_mentorFileId_fkey" FOREIGN KEY ("mentorFileId") REFERENCES "MentorFile"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "MentorFileComment" ADD CONSTRAINT "MentorFileComment_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE "MentorFileComment" ADD CONSTRAINT "MentorFileComment_parentCommentId_fkey" FOREIGN KEY ("parentCommentId") REFERENCES "MentorFileComment"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- SubmissionPromotionEvent
|
||||
ALTER TABLE "SubmissionPromotionEvent" ADD CONSTRAINT "SubmissionPromotionEvent_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "SubmissionPromotionEvent" ADD CONSTRAINT "SubmissionPromotionEvent_roundId_fkey" FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "SubmissionPromotionEvent" ADD CONSTRAINT "SubmissionPromotionEvent_sourceFileId_fkey" FOREIGN KEY ("sourceFileId") REFERENCES "MentorFile"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
ALTER TABLE "SubmissionPromotionEvent" ADD CONSTRAINT "SubmissionPromotionEvent_promotedById_fkey" FOREIGN KEY ("promotedById") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- DeliberationSession
|
||||
ALTER TABLE "DeliberationSession" ADD CONSTRAINT "DeliberationSession_competitionId_fkey" FOREIGN KEY ("competitionId") REFERENCES "Competition"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "DeliberationSession" ADD CONSTRAINT "DeliberationSession_roundId_fkey" FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- DeliberationVote
|
||||
ALTER TABLE "DeliberationVote" ADD CONSTRAINT "DeliberationVote_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "DeliberationSession"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "DeliberationVote" ADD CONSTRAINT "DeliberationVote_juryMemberId_fkey" FOREIGN KEY ("juryMemberId") REFERENCES "JuryGroupMember"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "DeliberationVote" ADD CONSTRAINT "DeliberationVote_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- DeliberationResult
|
||||
ALTER TABLE "DeliberationResult" ADD CONSTRAINT "DeliberationResult_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "DeliberationSession"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "DeliberationResult" ADD CONSTRAINT "DeliberationResult_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- DeliberationParticipant
|
||||
ALTER TABLE "DeliberationParticipant" ADD CONSTRAINT "DeliberationParticipant_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "DeliberationSession"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "DeliberationParticipant" ADD CONSTRAINT "DeliberationParticipant_userId_fkey" FOREIGN KEY ("userId") REFERENCES "JuryGroupMember"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "DeliberationParticipant" ADD CONSTRAINT "DeliberationParticipant_replacedById_fkey" FOREIGN KEY ("replacedById") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- ResultLock
|
||||
ALTER TABLE "ResultLock" ADD CONSTRAINT "ResultLock_competitionId_fkey" FOREIGN KEY ("competitionId") REFERENCES "Competition"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "ResultLock" ADD CONSTRAINT "ResultLock_roundId_fkey" FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "ResultLock" ADD CONSTRAINT "ResultLock_lockedById_fkey" FOREIGN KEY ("lockedById") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- ResultUnlockEvent
|
||||
ALTER TABLE "ResultUnlockEvent" ADD CONSTRAINT "ResultUnlockEvent_resultLockId_fkey" FOREIGN KEY ("resultLockId") REFERENCES "ResultLock"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "ResultUnlockEvent" ADD CONSTRAINT "ResultUnlockEvent_unlockedById_fkey" FOREIGN KEY ("unlockedById") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- FKs on modified existing tables
|
||||
ALTER TABLE "Assignment" ADD CONSTRAINT "Assignment_juryGroupId_fkey" FOREIGN KEY ("juryGroupId") REFERENCES "JuryGroup"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
ALTER TABLE "SpecialAward" ADD CONSTRAINT "SpecialAward_competitionId_fkey" FOREIGN KEY ("competitionId") REFERENCES "Competition"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
ALTER TABLE "SpecialAward" ADD CONSTRAINT "SpecialAward_evaluationRoundId_fkey" FOREIGN KEY ("evaluationRoundId") REFERENCES "Round"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
ALTER TABLE "SpecialAward" ADD CONSTRAINT "SpecialAward_juryGroupId_fkey" FOREIGN KEY ("juryGroupId") REFERENCES "JuryGroup"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
ALTER TABLE "MentorMessage" ADD CONSTRAINT "MentorMessage_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "MentorAssignment"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "ProjectFile" ADD CONSTRAINT "ProjectFile_submissionWindowId_fkey" FOREIGN KEY ("submissionWindowId") REFERENCES "SubmissionWindow"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
ALTER TABLE "ProjectFile" ADD CONSTRAINT "ProjectFile_submissionFileRequirementId_fkey" FOREIGN KEY ("submissionFileRequirementId") REFERENCES "SubmissionFileRequirement"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,3 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "JuryGroupMember" ADD COLUMN "selfServiceCap" INTEGER,
|
||||
ADD COLUMN "selfServiceRatio" DOUBLE PRECISION;
|
||||
300
prisma/migrations/20260215200000_phase7_fk_renames/migration.sql
Normal file
300
prisma/migrations/20260215200000_phase7_fk_renames/migration.sql
Normal file
@@ -0,0 +1,300 @@
|
||||
-- =============================================================================
|
||||
-- Phase 7/8 Migration Part 1: Rename stageId → roundId on 15 tables
|
||||
-- =============================================================================
|
||||
-- This migration renames stageId columns to roundId and updates FK constraints
|
||||
-- to point to the Round table instead of Stage table.
|
||||
|
||||
-- ─── 1. EvaluationForm ───────────────────────────────────────────────────────
|
||||
|
||||
-- Drop FK constraint
|
||||
ALTER TABLE "EvaluationForm" DROP CONSTRAINT IF EXISTS "EvaluationForm_stageId_fkey";
|
||||
|
||||
-- Drop indexes
|
||||
DROP INDEX IF EXISTS "EvaluationForm_stageId_version_key";
|
||||
DROP INDEX IF EXISTS "EvaluationForm_stageId_isActive_idx";
|
||||
|
||||
-- Rename column
|
||||
ALTER TABLE "EvaluationForm" RENAME COLUMN "stageId" TO "roundId";
|
||||
|
||||
-- Recreate indexes with new name
|
||||
CREATE UNIQUE INDEX "EvaluationForm_roundId_version_key" ON "EvaluationForm"("roundId", "version");
|
||||
CREATE INDEX "EvaluationForm_roundId_isActive_idx" ON "EvaluationForm"("roundId", "isActive");
|
||||
|
||||
-- Recreate FK pointing to Round
|
||||
ALTER TABLE "EvaluationForm" ADD CONSTRAINT "EvaluationForm_roundId_fkey"
|
||||
FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- ─── 2. FileRequirement ──────────────────────────────────────────────────────
|
||||
|
||||
-- Drop FK constraint
|
||||
ALTER TABLE "FileRequirement" DROP CONSTRAINT IF EXISTS "FileRequirement_stageId_fkey";
|
||||
|
||||
-- Drop index
|
||||
DROP INDEX IF EXISTS "FileRequirement_stageId_idx";
|
||||
|
||||
-- Rename column
|
||||
ALTER TABLE "FileRequirement" RENAME COLUMN "stageId" TO "roundId";
|
||||
|
||||
-- Recreate index
|
||||
CREATE INDEX "FileRequirement_roundId_idx" ON "FileRequirement"("roundId");
|
||||
|
||||
-- Recreate FK pointing to Round
|
||||
ALTER TABLE "FileRequirement" ADD CONSTRAINT "FileRequirement_roundId_fkey"
|
||||
FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- ─── 3. Assignment ───────────────────────────────────────────────────────────
|
||||
|
||||
-- Drop FK constraint
|
||||
ALTER TABLE "Assignment" DROP CONSTRAINT IF EXISTS "Assignment_stageId_fkey";
|
||||
|
||||
-- Drop indexes and unique constraint
|
||||
DROP INDEX IF EXISTS "Assignment_userId_projectId_stageId_key";
|
||||
DROP INDEX IF EXISTS "Assignment_stageId_idx";
|
||||
|
||||
-- Rename column
|
||||
ALTER TABLE "Assignment" RENAME COLUMN "stageId" TO "roundId";
|
||||
|
||||
-- Recreate unique constraint and index with new name
|
||||
CREATE UNIQUE INDEX "Assignment_userId_projectId_roundId_key" ON "Assignment"("userId", "projectId", "roundId");
|
||||
CREATE INDEX "Assignment_roundId_idx" ON "Assignment"("roundId");
|
||||
|
||||
-- Recreate FK pointing to Round
|
||||
ALTER TABLE "Assignment" ADD CONSTRAINT "Assignment_roundId_fkey"
|
||||
FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- ─── 4. GracePeriod ──────────────────────────────────────────────────────────
|
||||
|
||||
-- Drop FK constraint
|
||||
ALTER TABLE "GracePeriod" DROP CONSTRAINT IF EXISTS "GracePeriod_stageId_fkey";
|
||||
|
||||
-- Drop indexes
|
||||
DROP INDEX IF EXISTS "GracePeriod_stageId_idx";
|
||||
DROP INDEX IF EXISTS "GracePeriod_stageId_userId_extendedUntil_idx";
|
||||
|
||||
-- Rename column
|
||||
ALTER TABLE "GracePeriod" RENAME COLUMN "stageId" TO "roundId";
|
||||
|
||||
-- Recreate indexes
|
||||
CREATE INDEX "GracePeriod_roundId_idx" ON "GracePeriod"("roundId");
|
||||
CREATE INDEX "GracePeriod_roundId_userId_extendedUntil_idx" ON "GracePeriod"("roundId", "userId", "extendedUntil");
|
||||
|
||||
-- Recreate FK pointing to Round
|
||||
ALTER TABLE "GracePeriod" ADD CONSTRAINT "GracePeriod_roundId_fkey"
|
||||
FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- ─── 5. LiveVotingSession ────────────────────────────────────────────────────
|
||||
|
||||
-- Drop FK constraint
|
||||
ALTER TABLE "LiveVotingSession" DROP CONSTRAINT IF EXISTS "LiveVotingSession_stageId_fkey";
|
||||
|
||||
-- Drop unique index
|
||||
DROP INDEX IF EXISTS "LiveVotingSession_stageId_key";
|
||||
|
||||
-- Rename column
|
||||
ALTER TABLE "LiveVotingSession" RENAME COLUMN "stageId" TO "roundId";
|
||||
|
||||
-- Recreate unique index
|
||||
CREATE UNIQUE INDEX "LiveVotingSession_roundId_key" ON "LiveVotingSession"("roundId");
|
||||
|
||||
-- Recreate FK pointing to Round (nullable)
|
||||
ALTER TABLE "LiveVotingSession" ADD CONSTRAINT "LiveVotingSession_roundId_fkey"
|
||||
FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- ─── 6. FilteringRule ────────────────────────────────────────────────────────
|
||||
|
||||
-- Drop FK constraint
|
||||
ALTER TABLE "FilteringRule" DROP CONSTRAINT IF EXISTS "FilteringRule_stageId_fkey";
|
||||
|
||||
-- Drop index
|
||||
DROP INDEX IF EXISTS "FilteringRule_stageId_idx";
|
||||
|
||||
-- Rename column
|
||||
ALTER TABLE "FilteringRule" RENAME COLUMN "stageId" TO "roundId";
|
||||
|
||||
-- Recreate index
|
||||
CREATE INDEX "FilteringRule_roundId_idx" ON "FilteringRule"("roundId");
|
||||
|
||||
-- Recreate FK pointing to Round
|
||||
ALTER TABLE "FilteringRule" ADD CONSTRAINT "FilteringRule_roundId_fkey"
|
||||
FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- ─── 7. FilteringResult ──────────────────────────────────────────────────────
|
||||
|
||||
-- Drop FK constraint
|
||||
ALTER TABLE "FilteringResult" DROP CONSTRAINT IF EXISTS "FilteringResult_stageId_fkey";
|
||||
|
||||
-- Drop indexes and unique constraint
|
||||
DROP INDEX IF EXISTS "FilteringResult_stageId_projectId_key";
|
||||
DROP INDEX IF EXISTS "FilteringResult_stageId_idx";
|
||||
|
||||
-- Rename column
|
||||
ALTER TABLE "FilteringResult" RENAME COLUMN "stageId" TO "roundId";
|
||||
|
||||
-- Recreate unique constraint and index
|
||||
CREATE UNIQUE INDEX "FilteringResult_roundId_projectId_key" ON "FilteringResult"("roundId", "projectId");
|
||||
CREATE INDEX "FilteringResult_roundId_idx" ON "FilteringResult"("roundId");
|
||||
|
||||
-- Recreate FK pointing to Round
|
||||
ALTER TABLE "FilteringResult" ADD CONSTRAINT "FilteringResult_roundId_fkey"
|
||||
FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- ─── 8. FilteringJob ─────────────────────────────────────────────────────────
|
||||
|
||||
-- Drop FK constraint
|
||||
ALTER TABLE "FilteringJob" DROP CONSTRAINT IF EXISTS "FilteringJob_stageId_fkey";
|
||||
|
||||
-- Drop index
|
||||
DROP INDEX IF EXISTS "FilteringJob_stageId_idx";
|
||||
|
||||
-- Rename column
|
||||
ALTER TABLE "FilteringJob" RENAME COLUMN "stageId" TO "roundId";
|
||||
|
||||
-- Recreate index
|
||||
CREATE INDEX "FilteringJob_roundId_idx" ON "FilteringJob"("roundId");
|
||||
|
||||
-- Recreate FK pointing to Round
|
||||
ALTER TABLE "FilteringJob" ADD CONSTRAINT "FilteringJob_roundId_fkey"
|
||||
FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- ─── 9. AssignmentJob ────────────────────────────────────────────────────────
|
||||
|
||||
-- Drop FK constraint
|
||||
ALTER TABLE "AssignmentJob" DROP CONSTRAINT IF EXISTS "AssignmentJob_stageId_fkey";
|
||||
|
||||
-- Drop index
|
||||
DROP INDEX IF EXISTS "AssignmentJob_stageId_idx";
|
||||
|
||||
-- Rename column
|
||||
ALTER TABLE "AssignmentJob" RENAME COLUMN "stageId" TO "roundId";
|
||||
|
||||
-- Recreate index
|
||||
CREATE INDEX "AssignmentJob_roundId_idx" ON "AssignmentJob"("roundId");
|
||||
|
||||
-- Recreate FK pointing to Round
|
||||
ALTER TABLE "AssignmentJob" ADD CONSTRAINT "AssignmentJob_roundId_fkey"
|
||||
FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- ─── 10. ReminderLog ─────────────────────────────────────────────────────────
|
||||
|
||||
-- Drop FK constraint
|
||||
ALTER TABLE "ReminderLog" DROP CONSTRAINT IF EXISTS "ReminderLog_stageId_fkey";
|
||||
|
||||
-- Drop indexes and unique constraint
|
||||
DROP INDEX IF EXISTS "ReminderLog_stageId_userId_type_key";
|
||||
DROP INDEX IF EXISTS "ReminderLog_stageId_idx";
|
||||
|
||||
-- Rename column
|
||||
ALTER TABLE "ReminderLog" RENAME COLUMN "stageId" TO "roundId";
|
||||
|
||||
-- Recreate unique constraint and index
|
||||
CREATE UNIQUE INDEX "ReminderLog_roundId_userId_type_key" ON "ReminderLog"("roundId", "userId", "type");
|
||||
CREATE INDEX "ReminderLog_roundId_idx" ON "ReminderLog"("roundId");
|
||||
|
||||
-- Recreate FK pointing to Round
|
||||
ALTER TABLE "ReminderLog" ADD CONSTRAINT "ReminderLog_roundId_fkey"
|
||||
FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- ─── 11. EvaluationSummary ───────────────────────────────────────────────────
|
||||
|
||||
-- Drop FK constraint
|
||||
ALTER TABLE "EvaluationSummary" DROP CONSTRAINT IF EXISTS "EvaluationSummary_stageId_fkey";
|
||||
|
||||
-- Drop indexes and unique constraint
|
||||
DROP INDEX IF EXISTS "EvaluationSummary_projectId_stageId_key";
|
||||
DROP INDEX IF EXISTS "EvaluationSummary_stageId_idx";
|
||||
|
||||
-- Rename column
|
||||
ALTER TABLE "EvaluationSummary" RENAME COLUMN "stageId" TO "roundId";
|
||||
|
||||
-- Recreate unique constraint and index
|
||||
CREATE UNIQUE INDEX "EvaluationSummary_projectId_roundId_key" ON "EvaluationSummary"("projectId", "roundId");
|
||||
CREATE INDEX "EvaluationSummary_roundId_idx" ON "EvaluationSummary"("roundId");
|
||||
|
||||
-- Recreate FK pointing to Round
|
||||
ALTER TABLE "EvaluationSummary" ADD CONSTRAINT "EvaluationSummary_roundId_fkey"
|
||||
FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- ─── 12. EvaluationDiscussion ────────────────────────────────────────────────
|
||||
|
||||
-- Drop FK constraint
|
||||
ALTER TABLE "EvaluationDiscussion" DROP CONSTRAINT IF EXISTS "EvaluationDiscussion_stageId_fkey";
|
||||
|
||||
-- Drop indexes and unique constraint
|
||||
DROP INDEX IF EXISTS "EvaluationDiscussion_projectId_stageId_key";
|
||||
DROP INDEX IF EXISTS "EvaluationDiscussion_stageId_idx";
|
||||
|
||||
-- Rename column
|
||||
ALTER TABLE "EvaluationDiscussion" RENAME COLUMN "stageId" TO "roundId";
|
||||
|
||||
-- Recreate unique constraint and index
|
||||
CREATE UNIQUE INDEX "EvaluationDiscussion_projectId_roundId_key" ON "EvaluationDiscussion"("projectId", "roundId");
|
||||
CREATE INDEX "EvaluationDiscussion_roundId_idx" ON "EvaluationDiscussion"("roundId");
|
||||
|
||||
-- Recreate FK pointing to Round
|
||||
ALTER TABLE "EvaluationDiscussion" ADD CONSTRAINT "EvaluationDiscussion_roundId_fkey"
|
||||
FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- ─── 13. Message ─────────────────────────────────────────────────────────────
|
||||
|
||||
-- Drop FK constraint
|
||||
ALTER TABLE "Message" DROP CONSTRAINT IF EXISTS "Message_stageId_fkey";
|
||||
|
||||
-- Drop index
|
||||
DROP INDEX IF EXISTS "Message_stageId_idx";
|
||||
|
||||
-- Rename column (nullable, so SET NULL on delete)
|
||||
ALTER TABLE "Message" RENAME COLUMN "stageId" TO "roundId";
|
||||
|
||||
-- Recreate index
|
||||
CREATE INDEX "Message_roundId_idx" ON "Message"("roundId");
|
||||
|
||||
-- Recreate FK pointing to Round with SET NULL
|
||||
ALTER TABLE "Message" ADD CONSTRAINT "Message_roundId_fkey"
|
||||
FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- ─── 14. Cohort ──────────────────────────────────────────────────────────────
|
||||
|
||||
-- Drop FK constraint
|
||||
ALTER TABLE "Cohort" DROP CONSTRAINT IF EXISTS "Cohort_stageId_fkey";
|
||||
|
||||
-- Drop indexes
|
||||
DROP INDEX IF EXISTS "Cohort_stageId_idx";
|
||||
|
||||
-- Rename column
|
||||
ALTER TABLE "Cohort" RENAME COLUMN "stageId" TO "roundId";
|
||||
|
||||
-- Recreate index
|
||||
CREATE INDEX "Cohort_roundId_idx" ON "Cohort"("roundId");
|
||||
|
||||
-- Recreate FK pointing to Round
|
||||
ALTER TABLE "Cohort" ADD CONSTRAINT "Cohort_roundId_fkey"
|
||||
FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- ─── 15. LiveProgressCursor ──────────────────────────────────────────────────
|
||||
|
||||
-- Drop FK constraint
|
||||
ALTER TABLE "LiveProgressCursor" DROP CONSTRAINT IF EXISTS "LiveProgressCursor_stageId_fkey";
|
||||
|
||||
-- Drop unique index
|
||||
DROP INDEX IF EXISTS "LiveProgressCursor_stageId_key";
|
||||
|
||||
-- Rename column
|
||||
ALTER TABLE "LiveProgressCursor" RENAME COLUMN "stageId" TO "roundId";
|
||||
|
||||
-- Recreate unique index
|
||||
CREATE UNIQUE INDEX "LiveProgressCursor_roundId_key" ON "LiveProgressCursor"("roundId");
|
||||
|
||||
-- Recreate FK pointing to Round
|
||||
ALTER TABLE "LiveProgressCursor" ADD CONSTRAINT "LiveProgressCursor_roundId_fkey"
|
||||
FOREIGN KEY ("roundId") REFERENCES "Round"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- ─── 16. SpecialAward: Drop trackId column ───────────────────────────────────
|
||||
|
||||
-- Drop FK constraint
|
||||
ALTER TABLE "SpecialAward" DROP CONSTRAINT IF EXISTS "SpecialAward_trackId_fkey";
|
||||
|
||||
-- Drop unique index
|
||||
DROP INDEX IF EXISTS "SpecialAward_trackId_key";
|
||||
|
||||
-- Drop column
|
||||
ALTER TABLE "SpecialAward" DROP COLUMN IF EXISTS "trackId";
|
||||
@@ -0,0 +1,31 @@
|
||||
-- =============================================================================
|
||||
-- Phase 7/8 Migration Part 2: Drop legacy Pipeline/Track/Stage tables and enums
|
||||
-- =============================================================================
|
||||
-- This migration removes the old stage-based architecture tables and enums.
|
||||
-- All data has been migrated to Competition/Round architecture.
|
||||
|
||||
-- ─── Drop Tables in FK-safe order ────────────────────────────────────────────
|
||||
|
||||
-- Drop ProjectStageState (references Track and Stage)
|
||||
DROP TABLE IF EXISTS "ProjectStageState" CASCADE;
|
||||
|
||||
-- Drop StageTransition (references Stage)
|
||||
DROP TABLE IF EXISTS "StageTransition" CASCADE;
|
||||
|
||||
-- Drop Stage (references Track)
|
||||
DROP TABLE IF EXISTS "Stage" CASCADE;
|
||||
|
||||
-- Drop Track (references Pipeline)
|
||||
DROP TABLE IF EXISTS "Track" CASCADE;
|
||||
|
||||
-- Drop Pipeline
|
||||
DROP TABLE IF EXISTS "Pipeline" CASCADE;
|
||||
|
||||
-- ─── Drop Enums ──────────────────────────────────────────────────────────────
|
||||
|
||||
DROP TYPE IF EXISTS "StageType";
|
||||
DROP TYPE IF EXISTS "TrackKind";
|
||||
DROP TYPE IF EXISTS "RoutingMode";
|
||||
DROP TYPE IF EXISTS "StageStatus";
|
||||
DROP TYPE IF EXISTS "ProjectStageStateValue";
|
||||
DROP TYPE IF EXISTS "DecisionMode";
|
||||
Reference in New Issue
Block a user