Comprehensive round system audit: fix 27 logic bugs, add manual project/assignment features, improve UI/UX
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m23s
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m23s
## Critical Logic Fixes (Tier 1) - Fix requiredReviews config key mismatch (always defaulted to 3) - Fix double-email + stageName/roundName metadata mismatch in notifications - Fix snake_case config reads in peer review (peerReviewEnabled was always blocked) - Add server-side COI check to evaluation submit (was client-only) - Fix hard-coded feedbackText.min(10) — now uses config values - Fix binaryDecision corruption in non-binary scoring modes - Fix advanceProjects: add competition/sort-order/status validations, move autoPass into tx - Fix removeFromRound: now cleans up orphaned Assignment records - Fix 3-day reminder sending wrong email template (was using 24h template) ## High-Priority Logic Fixes (Tier 2) - Add project state transition whitelist (prevent invalid transitions like REJECTED→PASSED) - Scope AI assignment job to jury group members (was querying all JURY_MEMBERs) - Add COI awareness to AI assignment generation - Enforce requireAllCriteriaScored server-side - Fix expireIntentsForRound nested transaction (now uses caller's tx) - Implement notifyOnEntry for advancement path - Implement notifyOnAdvance (was dead config) - Fix checkRequirementsAndTransition for SubmissionFileRequirement model ## New Features (Tier 3) - Add Project to Round: dialog with "Create New" and "From Pool" tabs - Assignment "By Project" mode: select project → assign multiple jurors - Backend: project.createAndAssignToRound procedure ## UI/UX Improvements (Tier 4+5) - Add AlertDialog confirmation to header status dropdown - Replace native confirm() with AlertDialog in assignments table - Jury stats card now display-only with "Change" link - Assignments tab restructured into logical card groups - Inline-editable round name in header - Back button shows destination label - Readiness checklist: green check instead of strikethrough - Gate assignments tab when no jury group assigned - Relative time on window stats card - Toast feedback on date saves - Disable advance button when no target round - COI section shows placeholder when empty - Round position shown as "Round X of Y" - InlineMemberCap edit icon always visible - Status badge tooltip with description - Add REMINDER_3_DAYS email template - Fix maybeSendEmail to respect notification preferences - Optimize bulk notification email loop Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -105,6 +105,7 @@ export const roundEngineRouter = router({
|
||||
input.newState,
|
||||
ctx.user.id,
|
||||
ctx.prisma,
|
||||
{ adminOverride: true },
|
||||
)
|
||||
if (!result.success) {
|
||||
throw new TRPCError({
|
||||
@@ -133,6 +134,7 @@ export const roundEngineRouter = router({
|
||||
input.newState,
|
||||
ctx.user.id,
|
||||
ctx.prisma,
|
||||
{ adminOverride: true },
|
||||
)
|
||||
}),
|
||||
|
||||
@@ -188,6 +190,14 @@ export const roundEngineRouter = router({
|
||||
|
||||
const roundIds = roundsToRemoveFrom.map((r) => r.id)
|
||||
|
||||
// Delete Assignment records first (Prisma cascade handles Evaluations)
|
||||
await ctx.prisma.assignment.deleteMany({
|
||||
where: {
|
||||
projectId: input.projectId,
|
||||
roundId: { in: roundIds },
|
||||
},
|
||||
})
|
||||
|
||||
// Delete ProjectRoundState entries for this project in all affected rounds
|
||||
const deleted = await ctx.prisma.projectRoundState.deleteMany({
|
||||
where: {
|
||||
@@ -238,6 +248,14 @@ export const roundEngineRouter = router({
|
||||
|
||||
const roundIds = roundsToRemoveFrom.map((r) => r.id)
|
||||
|
||||
// Delete Assignment records first (Prisma cascade handles Evaluations)
|
||||
await ctx.prisma.assignment.deleteMany({
|
||||
where: {
|
||||
projectId: { in: input.projectIds },
|
||||
roundId: { in: roundIds },
|
||||
},
|
||||
})
|
||||
|
||||
const deleted = await ctx.prisma.projectRoundState.deleteMany({
|
||||
where: {
|
||||
projectId: { in: input.projectIds },
|
||||
|
||||
Reference in New Issue
Block a user