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

@@ -34,7 +34,7 @@ export const projectRouter = router({
.input(
z.object({
programId: z.string().optional(),
stageId: z.string().optional(),
roundId: z.string().optional(),
status: z
.enum([
'SUBMITTED',
@@ -55,8 +55,8 @@ export const projectRouter = router({
'REJECTED',
])
).optional(),
excludeInStageId: z.string().optional(), // Exclude projects already in this stage
unassignedOnly: z.boolean().optional(), // Projects not in any stage
excludeInRoundId: z.string().optional(), // Exclude projects already in this round
unassignedOnly: z.boolean().optional(), // Projects not in any round
search: z.string().optional(),
tags: z.array(z.string()).optional(),
competitionCategory: z.enum(['STARTUP', 'BUSINESS_CONCEPT']).optional(),
@@ -76,7 +76,7 @@ export const projectRouter = router({
)
.query(async ({ ctx, input }) => {
const {
programId, stageId, excludeInStageId, status, statuses, unassignedOnly, search, tags,
programId, roundId, excludeInRoundId, status, statuses, unassignedOnly, search, tags,
competitionCategory, oceanIssue, country,
wantsMentorship, hasFiles, hasAssignments,
page, perPage,
@@ -89,19 +89,19 @@ export const projectRouter = router({
// Filter by program
if (programId) where.programId = programId
// Filter by stage (via ProjectStageState join)
if (stageId) {
where.stageStates = { some: { stageId } }
// Filter by round (via RoundAssignment join)
if (roundId) {
where.roundAssignments = { some: { roundId } }
}
// Exclude projects already in a specific stage
if (excludeInStageId) {
where.stageStates = { none: { stageId: excludeInStageId } }
// Exclude projects already in a specific round
if (excludeInRoundId) {
where.roundAssignments = { none: { roundId: excludeInRoundId } }
}
// Filter by unassigned (not in any stage)
// Filter by unassigned (not in any round)
if (unassignedOnly) {
where.stageStates = { none: {} }
where.roundAssignments = { none: {} }
}
// Status filter
@@ -171,8 +171,8 @@ export const projectRouter = router({
.input(
z.object({
programId: z.string().optional(),
stageId: z.string().optional(),
excludeInStageId: z.string().optional(),
roundId: z.string().optional(),
excludeInRoundId: z.string().optional(),
unassignedOnly: z.boolean().optional(),
search: z.string().optional(),
statuses: z.array(
@@ -201,7 +201,7 @@ export const projectRouter = router({
)
.query(async ({ ctx, input }) => {
const {
programId, stageId, excludeInStageId, unassignedOnly,
programId, roundId, excludeInRoundId, unassignedOnly,
search, statuses, tags,
competitionCategory, oceanIssue, country,
wantsMentorship, hasFiles, hasAssignments,
@@ -210,14 +210,14 @@ export const projectRouter = router({
const where: Record<string, unknown> = {}
if (programId) where.programId = programId
if (stageId) {
where.stageStates = { some: { stageId } }
if (roundId) {
where.roundAssignments = { some: { roundId } }
}
if (excludeInStageId) {
where.stageStates = { none: { stageId: excludeInStageId } }
if (excludeInRoundId) {
where.roundAssignments = { none: { roundId: excludeInRoundId } }
}
if (unassignedOnly) {
where.stageStates = { none: {} }
where.roundAssignments = { none: {} }
}
if (statuses?.length) where.status = { in: statuses }
if (tags && tags.length > 0) where.tags = { hasSome: tags }
@@ -1072,7 +1072,7 @@ export const projectRouter = router({
const where: Record<string, unknown> = {
programId,
stageStates: { none: {} }, // Projects not assigned to any stage
roundAssignments: { none: {} }, // Projects not assigned to any round
}
if (search) {