feat(finalist): unenroll reverses round membership + confirmation
Adds finalist.unenroll(projectId, roundId) which deletes the FinalistConfirmation (cascading AttendingMember/FlightDetail/ VisaApplication/MemberLunchPick) and the LIVE_FINAL ProjectRoundState, then logs a FINALIST_UNENROLL audit entry. Safe no-op when no rows exist. Tests cover ADMIN_CONFIRM enrolled teardown and the no-rows path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1273,4 +1273,49 @@ export const finalistRouter = router({
|
||||
|
||||
return { enrolled, emailed, adminConfirmed, skipped }
|
||||
}),
|
||||
|
||||
/**
|
||||
* Reverse enrollment: removes a project from the LIVE_FINAL round and
|
||||
* deletes its FinalistConfirmation (cascade removes AttendingMember,
|
||||
* FlightDetail, VisaApplication, and MemberLunchPick rows).
|
||||
*
|
||||
* Mentor assignments (tied to the MENTORING round) are intentionally
|
||||
* left untouched. Safe to call even if the project was never enrolled
|
||||
* (deleteMany is a no-op when no rows match).
|
||||
*/
|
||||
unenroll: adminProcedure
|
||||
.input(
|
||||
z.object({
|
||||
projectId: z.string(),
|
||||
roundId: z.string(), // the LIVE_FINAL round
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
// Step 1: Delete the FinalistConfirmation (cascade removes AttendingMember
|
||||
// / FlightDetail / VisaApplication / MemberLunchPick).
|
||||
// deleteMany is no-op-safe when no row exists.
|
||||
await ctx.prisma.finalistConfirmation.deleteMany({
|
||||
where: { projectId: input.projectId },
|
||||
})
|
||||
|
||||
// Step 2: Delete the LIVE_FINAL ProjectRoundState.
|
||||
await ctx.prisma.projectRoundState.deleteMany({
|
||||
where: { projectId: input.projectId, roundId: input.roundId },
|
||||
})
|
||||
|
||||
// Step 3: Audit log
|
||||
await logAudit({
|
||||
prisma: ctx.prisma,
|
||||
userId: ctx.user.id,
|
||||
action: 'FINALIST_UNENROLL',
|
||||
entityType: 'Project',
|
||||
entityId: input.projectId,
|
||||
detailsJson: {
|
||||
projectId: input.projectId,
|
||||
roundId: input.roundId,
|
||||
},
|
||||
})
|
||||
|
||||
return { ok: true }
|
||||
}),
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user