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:
@@ -5,12 +5,12 @@ import { logAudit } from '@/server/utils/audit'
|
||||
|
||||
export const cohortRouter = router({
|
||||
/**
|
||||
* Create a new cohort within a stage
|
||||
* Create a new cohort within a round
|
||||
*/
|
||||
create: adminProcedure
|
||||
.input(
|
||||
z.object({
|
||||
stageId: z.string(),
|
||||
roundId: z.string(),
|
||||
name: z.string().min(1).max(255),
|
||||
votingMode: z.enum(['simple', 'criteria', 'ranked']).default('simple'),
|
||||
windowOpenAt: z.date().optional(),
|
||||
@@ -18,18 +18,11 @@ export const cohortRouter = router({
|
||||
})
|
||||
)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
// Verify stage exists and is of a type that supports cohorts
|
||||
const stage = await ctx.prisma.stage.findUniqueOrThrow({
|
||||
where: { id: input.stageId },
|
||||
// Verify round exists
|
||||
const round = await ctx.prisma.round.findUniqueOrThrow({
|
||||
where: { id: input.roundId },
|
||||
})
|
||||
|
||||
if (stage.stageType !== 'LIVE_FINAL' && stage.stageType !== 'SELECTION') {
|
||||
throw new TRPCError({
|
||||
code: 'BAD_REQUEST',
|
||||
message: 'Cohorts can only be created in LIVE_FINAL or SELECTION stages',
|
||||
})
|
||||
}
|
||||
|
||||
// Validate window dates
|
||||
if (input.windowOpenAt && input.windowCloseAt) {
|
||||
if (input.windowCloseAt <= input.windowOpenAt) {
|
||||
@@ -43,7 +36,7 @@ export const cohortRouter = router({
|
||||
const cohort = await ctx.prisma.$transaction(async (tx) => {
|
||||
const created = await tx.cohort.create({
|
||||
data: {
|
||||
stageId: input.stageId,
|
||||
roundId: input.roundId,
|
||||
name: input.name,
|
||||
votingMode: input.votingMode,
|
||||
windowOpenAt: input.windowOpenAt ?? null,
|
||||
@@ -58,7 +51,7 @@ export const cohortRouter = router({
|
||||
entityType: 'Cohort',
|
||||
entityId: created.id,
|
||||
detailsJson: {
|
||||
stageId: input.stageId,
|
||||
roundId: input.roundId,
|
||||
name: input.name,
|
||||
votingMode: input.votingMode,
|
||||
},
|
||||
@@ -244,13 +237,13 @@ export const cohortRouter = router({
|
||||
}),
|
||||
|
||||
/**
|
||||
* List cohorts for a stage
|
||||
* List cohorts for a round
|
||||
*/
|
||||
list: protectedProcedure
|
||||
.input(z.object({ stageId: z.string() }))
|
||||
.input(z.object({ roundId: z.string() }))
|
||||
.query(async ({ ctx, input }) => {
|
||||
return ctx.prisma.cohort.findMany({
|
||||
where: { stageId: input.stageId },
|
||||
where: { roundId: input.roundId },
|
||||
orderBy: { createdAt: 'asc' },
|
||||
include: {
|
||||
_count: { select: { projects: true } },
|
||||
@@ -267,18 +260,11 @@ export const cohortRouter = router({
|
||||
const cohort = await ctx.prisma.cohort.findUniqueOrThrow({
|
||||
where: { id: input.id },
|
||||
include: {
|
||||
stage: {
|
||||
round: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
stageType: true,
|
||||
track: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
pipeline: { select: { id: true, name: true } },
|
||||
},
|
||||
},
|
||||
competition: { select: { id: true, name: true } },
|
||||
},
|
||||
},
|
||||
projects: {
|
||||
@@ -298,7 +284,7 @@ export const cohortRouter = router({
|
||||
},
|
||||
})
|
||||
|
||||
// Get vote counts per project in the cohort's stage session
|
||||
// Get vote counts per project in the cohort's round session
|
||||
const projectIds = cohort.projects.map((p) => p.projectId)
|
||||
const voteSummary =
|
||||
projectIds.length > 0
|
||||
@@ -306,7 +292,7 @@ export const cohortRouter = router({
|
||||
by: ['projectId'],
|
||||
where: {
|
||||
projectId: { in: projectIds },
|
||||
session: { stageId: cohort.stage.id },
|
||||
session: { roundId: cohort.round.id },
|
||||
},
|
||||
_count: true,
|
||||
_avg: { score: true },
|
||||
|
||||
Reference in New Issue
Block a user