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:
@@ -42,14 +42,10 @@ async function ProgramsContent() {
|
||||
const programs = await prisma.program.findMany({
|
||||
// Note: PROGRAM_ADMIN filtering should be handled via middleware or a separate relation
|
||||
include: {
|
||||
pipelines: {
|
||||
competitions: {
|
||||
include: {
|
||||
tracks: {
|
||||
include: {
|
||||
stages: {
|
||||
select: { id: true, status: true },
|
||||
},
|
||||
},
|
||||
rounds: {
|
||||
select: { id: true, status: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -57,16 +53,14 @@ async function ProgramsContent() {
|
||||
orderBy: { createdAt: 'desc' },
|
||||
})
|
||||
|
||||
// Flatten stages per program for convenience
|
||||
const programsWithStageCounts = programs.map((p) => {
|
||||
const allStages = p.pipelines.flatMap((pl) =>
|
||||
pl.tracks.flatMap((t) => t.stages)
|
||||
)
|
||||
const activeStages = allStages.filter((s) => s.status === 'STAGE_ACTIVE')
|
||||
return { ...p, stageCount: allStages.length, activeStageCount: activeStages.length }
|
||||
// Flatten rounds per program for convenience
|
||||
const programsWithRoundCounts = programs.map((p) => {
|
||||
const allRounds = p.competitions.flatMap((c) => c.rounds)
|
||||
const activeRounds = allRounds.filter((r) => r.status === 'ROUND_ACTIVE')
|
||||
return { ...p, roundCount: allRounds.length, activeRoundCount: activeRounds.length }
|
||||
})
|
||||
|
||||
if (programsWithStageCounts.length === 0) {
|
||||
if (programsWithRoundCounts.length === 0) {
|
||||
return (
|
||||
<Card>
|
||||
<CardContent className="flex flex-col items-center justify-center py-12 text-center">
|
||||
@@ -102,14 +96,14 @@ async function ProgramsContent() {
|
||||
<TableRow>
|
||||
<TableHead>Program</TableHead>
|
||||
<TableHead>Year</TableHead>
|
||||
<TableHead>Stages</TableHead>
|
||||
<TableHead>Rounds</TableHead>
|
||||
<TableHead>Status</TableHead>
|
||||
<TableHead>Created</TableHead>
|
||||
<TableHead className="text-right">Actions</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{programsWithStageCounts.map((program) => (
|
||||
{programsWithRoundCounts.map((program) => (
|
||||
<TableRow key={program.id}>
|
||||
<TableCell>
|
||||
<div>
|
||||
@@ -124,10 +118,10 @@ async function ProgramsContent() {
|
||||
<TableCell>{program.year}</TableCell>
|
||||
<TableCell>
|
||||
<div>
|
||||
<p>{program.stageCount} total</p>
|
||||
{program.activeStageCount > 0 && (
|
||||
<p>{program.roundCount} total</p>
|
||||
{program.activeRoundCount > 0 && (
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{program.activeStageCount} active
|
||||
{program.activeRoundCount} active
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
@@ -176,7 +170,7 @@ async function ProgramsContent() {
|
||||
|
||||
{/* Mobile card view */}
|
||||
<div className="space-y-4 md:hidden">
|
||||
{programsWithStageCounts.map((program) => (
|
||||
{programsWithRoundCounts.map((program) => (
|
||||
<Card key={program.id}>
|
||||
<CardHeader className="pb-3">
|
||||
<div className="flex items-start justify-between">
|
||||
@@ -193,7 +187,7 @@ async function ProgramsContent() {
|
||||
<div className="flex items-center justify-between text-sm">
|
||||
<span className="text-muted-foreground">Stages</span>
|
||||
<span>
|
||||
{program.stageCount} ({program.activeStageCount} active)
|
||||
{program.roundCount} ({program.activeRoundCount} active)
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between text-sm">
|
||||
|
||||
Reference in New Issue
Block a user