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

@@ -87,18 +87,20 @@ function ProjectDetailContent({ projectId }: { projectId: string }) {
// Fetch files (flat list for backward compatibility)
const { data: files } = trpc.file.listByProject.useQuery({ projectId })
// Fetch file requirements from the pipeline's intake stage
const { data: requirementsData } = trpc.file.getProjectRequirements.useQuery(
{ projectId },
{ enabled: !!project }
)
// Fetch file requirements from the competition's intake round
// Note: This procedure may need to be updated or removed depending on new system
// const { data: requirementsData } = trpc.file.getProjectRequirements.useQuery(
// { projectId },
// { enabled: !!project }
// )
const requirementsData = null // Placeholder until procedure is updated
// Fetch available stages for upload selector (if project has a programId)
// Fetch available rounds for upload selector (if project has a programId)
const { data: programData } = trpc.program.get.useQuery(
{ id: project?.programId || '' },
{ enabled: !!project?.programId }
)
const availableStages = (programData?.stages as Array<{ id: string; name: string }>) || []
const availableRounds = (programData?.stages as Array<{ id: string; name: string }>) || []
const utils = trpc.useUtils()
@@ -528,13 +530,13 @@ function ProjectDetailContent({ projectId }: { projectId: string }) {
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
{/* Required Documents from Pipeline Intake Stage */}
{requirementsData && requirementsData.requirements.length > 0 && (
{/* Required Documents from Competition Intake Round */}
{requirementsData && (requirementsData as { requirements: Array<{ id?: string; name: string; isRequired?: boolean; description?: string; maxSizeMB?: number; fulfilled: boolean; fulfilledFile?: { fileName: string } }> }).requirements?.length > 0 && (
<>
<div>
<p className="text-sm font-semibold mb-3">Required Documents</p>
<div className="grid gap-2">
{requirementsData.requirements.map((req, idx) => {
{(requirementsData as { requirements: Array<{ id?: string; name: string; isRequired?: boolean; description?: string; maxSizeMB?: number; fulfilled: boolean; fulfilledFile?: { fileName: string } }> }).requirements.map((req: { id?: string; name: string; isRequired?: boolean; description?: string; maxSizeMB?: number; fulfilled: boolean; fulfilledFile?: { fileName: string } }, idx: number) => {
const isFulfilled = req.fulfilled
return (
<div
@@ -592,16 +594,16 @@ function ProjectDetailContent({ projectId }: { projectId: string }) {
{/* Additional Documents Upload */}
<div>
<p className="text-sm font-semibold mb-3">
{requirementsData && requirementsData.requirements.length > 0
{requirementsData && (requirementsData as { requirements: unknown[] }).requirements?.length > 0
? 'Additional Documents'
: 'Upload New Files'}
</p>
<FileUpload
projectId={projectId}
availableStages={availableStages?.map((s: { id: string; name: string }) => ({ id: s.id, name: s.name }))}
availableRounds={availableRounds?.map((s: { id: string; name: string }) => ({ id: s.id, name: s.name }))}
onUploadComplete={() => {
utils.file.listByProject.invalidate({ projectId })
utils.file.getProjectRequirements.invalidate({ projectId })
// utils.file.getProjectRequirements.invalidate({ projectId })
}}
/>
</div>
@@ -757,7 +759,7 @@ function ProjectDetailContent({ projectId }: { projectId: string }) {
{assignments && assignments.length > 0 && stats && stats.totalEvaluations > 0 && (
<EvaluationSummaryCard
projectId={projectId}
stageId={assignments[0].stageId}
roundId={assignments[0].roundId}
/>
)}
</div>