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

@@ -13,23 +13,19 @@ interface LiveVotingCriterion {
export const liveVotingRouter = router({
/**
* Get or create a live voting session for a stage
* Get or create a live voting session for a round
*/
getSession: adminProcedure
.input(z.object({ stageId: z.string() }))
.input(z.object({ roundId: z.string() }))
.query(async ({ ctx, input }) => {
let session = await ctx.prisma.liveVotingSession.findUnique({
where: { stageId: input.stageId },
where: { roundId: input.roundId },
include: {
stage: {
round: {
include: {
track: {
competition: {
include: {
pipeline: {
include: {
program: { select: { name: true, year: true } },
},
},
program: { select: { name: true, year: true } },
},
},
},
@@ -40,18 +36,14 @@ export const liveVotingRouter = router({
if (!session) {
session = await ctx.prisma.liveVotingSession.create({
data: {
stageId: input.stageId,
roundId: input.roundId,
},
include: {
stage: {
round: {
include: {
track: {
competition: {
include: {
pipeline: {
include: {
program: { select: { name: true, year: true } },
},
},
program: { select: { name: true, year: true } },
},
},
},
@@ -94,15 +86,11 @@ export const liveVotingRouter = router({
const session = await ctx.prisma.liveVotingSession.findUniqueOrThrow({
where: { id: input.sessionId },
include: {
stage: {
round: {
include: {
track: {
competition: {
include: {
pipeline: {
include: {
program: { select: { name: true, year: true } },
},
},
program: { select: { name: true, year: true } },
},
},
},
@@ -144,7 +132,7 @@ export const liveVotingRouter = router({
votingMode: session.votingMode,
criteriaJson: session.criteriaJson,
},
stage: session.stage,
round: session.round,
currentProject,
userVote,
timeRemaining,
@@ -160,15 +148,11 @@ export const liveVotingRouter = router({
const session = await ctx.prisma.liveVotingSession.findUniqueOrThrow({
where: { id: input.sessionId },
include: {
stage: {
round: {
include: {
track: {
competition: {
include: {
pipeline: {
include: {
program: { select: { name: true, year: true } },
},
},
program: { select: { name: true, year: true } },
},
},
},
@@ -209,7 +193,7 @@ export const liveVotingRouter = router({
currentProjectId: session.currentProjectId,
votingEndsAt: session.votingEndsAt,
},
stage: session.stage,
round: session.round,
projects: projectsWithScores,
}
}),
@@ -569,15 +553,11 @@ export const liveVotingRouter = router({
const session = await ctx.prisma.liveVotingSession.findUniqueOrThrow({
where: { id: input.sessionId },
include: {
stage: {
round: {
include: {
track: {
competition: {
include: {
pipeline: {
include: {
program: { select: { name: true, year: true } },
},
},
program: { select: { name: true, year: true } },
},
},
},
@@ -929,16 +909,12 @@ export const liveVotingRouter = router({
audienceVotingMode: true,
audienceRequireId: true,
audienceMaxFavorites: true,
stage: {
round: {
select: {
name: true,
track: {
competition: {
select: {
pipeline: {
select: {
program: { select: { name: true, year: true } },
},
},
program: { select: { name: true, year: true } },
},
},
},