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

View File

@@ -50,7 +50,7 @@ interface RequirementUploadSlotProps {
requirement: FileRequirement
existingFile?: UploadedFile | null
projectId: string
stageId: string
roundId: string
onFileChange?: () => void
disabled?: boolean
}
@@ -59,7 +59,7 @@ export function RequirementUploadSlot({
requirement,
existingFile,
projectId,
stageId,
roundId,
onFileChange,
disabled = false,
}: RequirementUploadSlotProps) {
@@ -110,13 +110,13 @@ export function RequirementUploadSlot({
try {
// Get presigned URL
const { url, bucket, objectKey, isLate, stageId: uploadStageId } =
const { url, bucket, objectKey, isLate, roundId: uploadRoundId } =
await getUploadUrl.mutateAsync({
projectId,
fileName: file.name,
mimeType: file.type,
fileType: 'OTHER',
stageId,
roundId,
requirementId: requirement.id,
})
@@ -150,7 +150,7 @@ export function RequirementUploadSlot({
fileType: 'OTHER',
bucket,
objectKey,
stageId: uploadStageId || stageId,
roundId: uploadRoundId || roundId,
isLate: isLate || false,
requirementId: requirement.id,
})
@@ -164,7 +164,7 @@ export function RequirementUploadSlot({
setProgress(0)
}
},
[projectId, stageId, requirement, acceptsMime, getUploadUrl, saveFileMetadata, onFileChange]
[projectId, roundId, requirement, acceptsMime, getUploadUrl, saveFileMetadata, onFileChange]
)
const handleDelete = useCallback(async () => {
@@ -309,22 +309,22 @@ export function RequirementUploadSlot({
interface RequirementUploadListProps {
projectId: string
stageId: string
roundId: string
disabled?: boolean
}
export function RequirementUploadList({ projectId, stageId, disabled }: RequirementUploadListProps) {
export function RequirementUploadList({ projectId, roundId, disabled }: RequirementUploadListProps) {
const utils = trpc.useUtils()
const { data: requirements = [] } = trpc.file.listRequirements.useQuery({
stageId,
roundId,
})
const { data: files = [] } = trpc.file.listByProject.useQuery({ projectId, stageId })
const { data: files = [] } = trpc.file.listByProject.useQuery({ projectId, roundId })
if (requirements.length === 0) return null
const handleFileChange = () => {
utils.file.listByProject.invalidate({ projectId, stageId })
utils.file.listByProject.invalidate({ projectId, roundId })
}
return (
@@ -353,7 +353,7 @@ export function RequirementUploadList({ projectId, stageId, disabled }: Requirem
: null
}
projectId={projectId}
stageId={stageId}
roundId={roundId}
onFileChange={handleFileChange}
disabled={disabled}
/>