Competition/Round architecture: full platform rewrite (Phases 1-9)
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:
2026-02-15 23:04:15 +01:00
parent 9ab4717f96
commit 6ca39c976b
349 changed files with 69938 additions and 28767 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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");

View File

@@ -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");

View File

@@ -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;

View File

@@ -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;

View File

@@ -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
-- =============================================================================

View File

@@ -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");

View File

@@ -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
-- =============================================================================

View File

@@ -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;

View File

@@ -0,0 +1,3 @@
-- AlterTable
ALTER TABLE "JuryGroupMember" ADD COLUMN "selfServiceCap" INTEGER,
ADD COLUMN "selfServiceRatio" DOUBLE PRECISION;

View 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";

View File

@@ -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";