refactor: tech debt batch 3 — type safety + assignment router split
All checks were successful
Build and Push Docker Image / build (push) Successful in 13m4s

#5 — Replaced 55x PrismaClient | any with proper Prisma types across 8 files
- Service files: PrismaClient | any → PrismaClient, tx: any → Prisma.TransactionClient
- Fixed 4 real bugs uncovered by typing:
  - mentor-workspace.ts: wrong FK fields (mentorAssignmentId → workspaceId, role → senderRole)
  - ai-shortlist.ts: untyped string passed to CompetitionCategory enum filter
  - result-lock.ts: unknown passed where Prisma.InputJsonValue required

#9 — Split assignment.ts (2,775 lines) into 6 focused files:
  - shared.ts (93 lines) — MOVABLE_EVAL_STATUSES, buildBatchNotifications, getCandidateJurors
  - assignment-crud.ts (473 lines) — 8 core CRUD procedures
  - assignment-suggestions.ts (880 lines) — AI suggestions + job runner
  - assignment-notifications.ts (138 lines) — 2 notification procedures
  - assignment-redistribution.ts (1,162 lines) — 8 reassign/transfer procedures
  - index.ts (15 lines) — barrel export with router merge, zero frontend changes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-10 12:47:06 +01:00
parent 1c78ecf21d
commit 6b40fe7726
16 changed files with 2836 additions and 2851 deletions

View File

@@ -74,7 +74,7 @@ const VALID_PROJECT_TRANSITIONS: Record<string, string[]> = {
export async function activateRound(
roundId: string,
actorId: string,
prisma: PrismaClient | any,
prisma: PrismaClient,
): Promise<RoundTransitionResult> {
try {
const round = await prisma.round.findUnique({
@@ -127,7 +127,7 @@ export async function activateRound(
windowData.windowOpenAt = now
}
const updated = await prisma.$transaction(async (tx: any) => {
const updated = await prisma.$transaction(async (tx: Prisma.TransactionClient) => {
const result = await tx.round.update({
where: { id: roundId },
data: { status: 'ROUND_ACTIVE', ...windowData },
@@ -234,7 +234,7 @@ export async function activateRound(
export async function closeRound(
roundId: string,
actorId: string,
prisma: PrismaClient | any,
prisma: PrismaClient,
): Promise<RoundTransitionResult> {
try {
const round = await prisma.round.findUnique({
@@ -267,7 +267,7 @@ export async function closeRound(
}
}
const updated = await prisma.$transaction(async (tx: any) => {
const updated = await prisma.$transaction(async (tx: Prisma.TransactionClient) => {
const result = await tx.round.update({
where: { id: roundId },
data: { status: 'ROUND_CLOSED' },
@@ -383,7 +383,7 @@ export async function closeRound(
export async function archiveRound(
roundId: string,
actorId: string,
prisma: PrismaClient | any,
prisma: PrismaClient,
): Promise<RoundTransitionResult> {
try {
const round = await prisma.round.findUnique({ where: { id: roundId } })
@@ -399,7 +399,7 @@ export async function archiveRound(
}
}
const updated = await prisma.$transaction(async (tx: any) => {
const updated = await prisma.$transaction(async (tx: Prisma.TransactionClient) => {
const result = await tx.round.update({
where: { id: roundId },
data: { status: 'ROUND_ARCHIVED' },
@@ -456,7 +456,7 @@ export async function archiveRound(
export async function reopenRound(
roundId: string,
actorId: string,
prisma: PrismaClient | any,
prisma: PrismaClient,
): Promise<RoundTransitionResult & { pausedRounds?: string[] }> {
try {
const round = await prisma.round.findUnique({
@@ -475,7 +475,7 @@ export async function reopenRound(
}
}
const result = await prisma.$transaction(async (tx: any) => {
const result = await prisma.$transaction(async (tx: Prisma.TransactionClient) => {
// Pause any subsequent active rounds in the same competition
const subsequentActiveRounds = await tx.round.findMany({
where: {
@@ -601,7 +601,7 @@ export async function transitionProject(
roundId: string,
newState: ProjectRoundStateValue,
actorId: string,
prisma: PrismaClient | any,
prisma: PrismaClient,
options?: { adminOverride?: boolean },
): Promise<ProjectRoundTransitionResult> {
try {
@@ -624,7 +624,7 @@ export async function transitionProject(
return { success: false, errors: [`Project ${projectId} not found`] }
}
const result = await prisma.$transaction(async (tx: any) => {
const result = await prisma.$transaction(async (tx: Prisma.TransactionClient) => {
const now = new Date()
// Upsert ProjectRoundState
@@ -722,7 +722,7 @@ export async function batchTransitionProjects(
roundId: string,
newState: ProjectRoundStateValue,
actorId: string,
prisma: PrismaClient | any,
prisma: PrismaClient,
options?: { adminOverride?: boolean },
): Promise<BatchProjectTransitionResult> {
const succeeded: string[] = []
@@ -754,7 +754,7 @@ export async function batchTransitionProjects(
export async function getProjectRoundStates(
roundId: string,
prisma: PrismaClient | any,
prisma: PrismaClient,
) {
const states = await prisma.projectRoundState.findMany({
where: { roundId },
@@ -803,7 +803,7 @@ export async function getProjectRoundStates(
export async function getProjectRoundState(
projectId: string,
roundId: string,
prisma: PrismaClient | any,
prisma: PrismaClient,
) {
return prisma.projectRoundState.findUnique({
where: { projectId_roundId: { projectId, roundId } },
@@ -823,7 +823,7 @@ export async function checkRequirementsAndTransition(
projectId: string,
roundId: string,
actorId: string,
prisma: PrismaClient | any,
prisma: PrismaClient,
): Promise<{ transitioned: boolean; newState?: string }> {
try {
// Get all required FileRequirements for this round (legacy model)
@@ -939,7 +939,7 @@ export async function batchCheckRequirementsAndTransition(
roundId: string,
projectIds: string[],
actorId: string,
prisma: PrismaClient | any,
prisma: PrismaClient,
): Promise<{ transitionedCount: number; projectIds: string[] }> {
if (projectIds.length === 0) return { transitionedCount: 0, projectIds: [] }
@@ -1051,7 +1051,7 @@ export async function triggerInProgressOnActivity(
projectId: string,
roundId: string,
actorId: string,
prisma: PrismaClient | any,
prisma: PrismaClient,
): Promise<void> {
try {
const prs = await prisma.projectRoundState.findUnique({
@@ -1078,7 +1078,7 @@ export async function checkEvaluationCompletionAndTransition(
projectId: string,
roundId: string,
actorId: string,
prisma: PrismaClient | any,
prisma: PrismaClient,
): Promise<{ transitioned: boolean }> {
try {
const prs = await prisma.projectRoundState.findUnique({