Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
/**
|
|
|
|
|
* Mentor Workspace Service
|
|
|
|
|
*
|
|
|
|
|
* Manages mentor-applicant workspace: activation, messaging, file management,
|
|
|
|
|
* and file promotion to official submissions. Operates on MentorAssignment,
|
|
|
|
|
* MentorMessage, MentorFile, MentorFileComment, SubmissionPromotionEvent.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import type { PrismaClient, Prisma } from '@prisma/client'
|
|
|
|
|
import { logAudit } from '@/server/utils/audit'
|
|
|
|
|
|
|
|
|
|
// ─── Types ──────────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
type WorkspaceResult = { success: boolean; errors?: string[] }
|
|
|
|
|
|
|
|
|
|
// ─── Workspace Activation ───────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Activate a mentor workspace for a given assignment.
|
|
|
|
|
*/
|
|
|
|
|
export async function activateWorkspace(
|
2026-03-10 12:47:06 +01:00
|
|
|
workspaceId: string,
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
actorId: string,
|
2026-03-10 12:47:06 +01:00
|
|
|
prisma: PrismaClient,
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
): Promise<WorkspaceResult> {
|
|
|
|
|
try {
|
|
|
|
|
const assignment = await prisma.mentorAssignment.findUnique({
|
2026-03-10 12:47:06 +01:00
|
|
|
where: { id: workspaceId },
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if (!assignment) {
|
|
|
|
|
return { success: false, errors: ['Mentor assignment not found'] }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (assignment.workspaceEnabled) {
|
|
|
|
|
return { success: false, errors: ['Workspace is already enabled'] }
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-10 12:47:06 +01:00
|
|
|
await prisma.$transaction(async (tx: Prisma.TransactionClient) => {
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
await tx.mentorAssignment.update({
|
2026-03-10 12:47:06 +01:00
|
|
|
where: { id: workspaceId },
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
data: {
|
|
|
|
|
workspaceEnabled: true,
|
|
|
|
|
workspaceOpenAt: new Date(),
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
await tx.decisionAuditLog.create({
|
|
|
|
|
data: {
|
|
|
|
|
eventType: 'mentor_workspace.activated',
|
|
|
|
|
entityType: 'MentorAssignment',
|
2026-03-10 12:47:06 +01:00
|
|
|
entityId: workspaceId,
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
actorId,
|
|
|
|
|
detailsJson: {
|
|
|
|
|
projectId: assignment.projectId,
|
|
|
|
|
mentorId: assignment.mentorId,
|
|
|
|
|
},
|
|
|
|
|
snapshotJson: { timestamp: new Date().toISOString(), emittedBy: 'mentor-workspace' },
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
await logAudit({
|
|
|
|
|
prisma: tx,
|
|
|
|
|
userId: actorId,
|
|
|
|
|
action: 'WORKSPACE_ACTIVATE',
|
|
|
|
|
entityType: 'MentorAssignment',
|
2026-03-10 12:47:06 +01:00
|
|
|
entityId: workspaceId,
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
detailsJson: { projectId: assignment.projectId },
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return { success: true }
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('[MentorWorkspace] activateWorkspace failed:', error)
|
|
|
|
|
return {
|
|
|
|
|
success: false,
|
|
|
|
|
errors: [error instanceof Error ? error.message : 'Unknown error'],
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ─── Messaging ──────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Send a message in a mentor workspace.
|
|
|
|
|
*/
|
|
|
|
|
export async function sendMessage(
|
|
|
|
|
params: {
|
2026-03-10 12:47:06 +01:00
|
|
|
workspaceId: string
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
senderId: string
|
|
|
|
|
message: string
|
|
|
|
|
role: 'MENTOR_ROLE' | 'APPLICANT_ROLE' | 'ADMIN_ROLE'
|
|
|
|
|
},
|
2026-03-10 12:47:06 +01:00
|
|
|
prisma: PrismaClient,
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
) {
|
|
|
|
|
const assignment = await prisma.mentorAssignment.findUnique({
|
2026-03-10 12:47:06 +01:00
|
|
|
where: { id: params.workspaceId },
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if (!assignment) {
|
|
|
|
|
throw new Error('Mentor assignment not found')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!assignment.workspaceEnabled) {
|
|
|
|
|
throw new Error('Workspace is not enabled for this assignment')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return prisma.mentorMessage.create({
|
|
|
|
|
data: {
|
2026-03-10 12:47:06 +01:00
|
|
|
workspaceId: params.workspaceId,
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
projectId: assignment.projectId,
|
|
|
|
|
senderId: params.senderId,
|
|
|
|
|
message: params.message,
|
2026-03-10 12:47:06 +01:00
|
|
|
senderRole: params.role,
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
},
|
|
|
|
|
include: {
|
|
|
|
|
sender: { select: { id: true, name: true, email: true } },
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get messages for a workspace.
|
|
|
|
|
*/
|
|
|
|
|
export async function getMessages(
|
2026-03-10 12:47:06 +01:00
|
|
|
workspaceId: string,
|
|
|
|
|
prisma: PrismaClient,
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
) {
|
|
|
|
|
return prisma.mentorMessage.findMany({
|
2026-03-10 12:47:06 +01:00
|
|
|
where: { workspaceId },
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
include: {
|
|
|
|
|
sender: { select: { id: true, name: true, email: true, role: true } },
|
|
|
|
|
},
|
|
|
|
|
orderBy: { createdAt: 'asc' },
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Mark a message as read.
|
|
|
|
|
*/
|
|
|
|
|
export async function markRead(
|
|
|
|
|
messageId: string,
|
2026-03-10 12:47:06 +01:00
|
|
|
prisma: PrismaClient,
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
): Promise<void> {
|
|
|
|
|
await prisma.mentorMessage.update({
|
|
|
|
|
where: { id: messageId },
|
|
|
|
|
data: { isRead: true },
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ─── File Management ────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Record a file upload in a workspace.
|
|
|
|
|
*/
|
|
|
|
|
export async function uploadFile(
|
|
|
|
|
params: {
|
2026-03-10 12:47:06 +01:00
|
|
|
workspaceId: string
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
uploadedByUserId: string
|
|
|
|
|
fileName: string
|
|
|
|
|
mimeType: string
|
|
|
|
|
size: number
|
|
|
|
|
bucket: string
|
|
|
|
|
objectKey: string
|
|
|
|
|
description?: string
|
|
|
|
|
},
|
2026-03-10 12:47:06 +01:00
|
|
|
prisma: PrismaClient,
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
) {
|
|
|
|
|
const assignment = await prisma.mentorAssignment.findUnique({
|
2026-03-10 12:47:06 +01:00
|
|
|
where: { id: params.workspaceId },
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if (!assignment) {
|
|
|
|
|
throw new Error('Mentor assignment not found')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!assignment.workspaceEnabled) {
|
|
|
|
|
throw new Error('Workspace is not enabled for this assignment')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return prisma.mentorFile.create({
|
|
|
|
|
data: {
|
2026-03-10 12:47:06 +01:00
|
|
|
mentorAssignmentId: params.workspaceId,
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
uploadedByUserId: params.uploadedByUserId,
|
|
|
|
|
fileName: params.fileName,
|
|
|
|
|
mimeType: params.mimeType,
|
|
|
|
|
size: params.size,
|
|
|
|
|
bucket: params.bucket,
|
|
|
|
|
objectKey: params.objectKey,
|
|
|
|
|
description: params.description,
|
|
|
|
|
},
|
|
|
|
|
include: {
|
|
|
|
|
uploadedBy: { select: { id: true, name: true, email: true } },
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add a comment to a file.
|
|
|
|
|
*/
|
|
|
|
|
export async function addFileComment(
|
|
|
|
|
params: {
|
|
|
|
|
mentorFileId: string
|
|
|
|
|
authorId: string
|
|
|
|
|
content: string
|
|
|
|
|
parentCommentId?: string
|
|
|
|
|
},
|
2026-03-10 12:47:06 +01:00
|
|
|
prisma: PrismaClient,
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
) {
|
|
|
|
|
return prisma.mentorFileComment.create({
|
|
|
|
|
data: {
|
|
|
|
|
mentorFileId: params.mentorFileId,
|
|
|
|
|
authorId: params.authorId,
|
|
|
|
|
content: params.content,
|
|
|
|
|
parentCommentId: params.parentCommentId,
|
|
|
|
|
},
|
|
|
|
|
include: {
|
|
|
|
|
author: { select: { id: true, name: true, email: true } },
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ─── File Promotion ─────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Promote a mentor file to an official submission.
|
|
|
|
|
* Creates SubmissionPromotionEvent and marks MentorFile.isPromoted = true.
|
|
|
|
|
*/
|
|
|
|
|
export async function promoteFile(
|
|
|
|
|
params: {
|
|
|
|
|
mentorFileId: string
|
|
|
|
|
roundId: string
|
|
|
|
|
slotKey: string
|
|
|
|
|
promotedById: string
|
|
|
|
|
},
|
2026-03-10 12:47:06 +01:00
|
|
|
prisma: PrismaClient,
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
): Promise<{ success: boolean; errors?: string[] }> {
|
|
|
|
|
try {
|
|
|
|
|
const file = await prisma.mentorFile.findUnique({
|
|
|
|
|
where: { id: params.mentorFileId },
|
|
|
|
|
include: {
|
|
|
|
|
mentorAssignment: { select: { projectId: true } },
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if (!file) {
|
|
|
|
|
return { success: false, errors: ['Mentor file not found'] }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (file.isPromoted) {
|
|
|
|
|
return { success: false, errors: ['File is already promoted'] }
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-10 12:47:06 +01:00
|
|
|
await prisma.$transaction(async (tx: Prisma.TransactionClient) => {
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
// Mark file as promoted
|
|
|
|
|
await tx.mentorFile.update({
|
|
|
|
|
where: { id: params.mentorFileId },
|
|
|
|
|
data: {
|
|
|
|
|
isPromoted: true,
|
|
|
|
|
promotedAt: new Date(),
|
|
|
|
|
promotedByUserId: params.promotedById,
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// Create promotion event
|
|
|
|
|
await tx.submissionPromotionEvent.create({
|
|
|
|
|
data: {
|
|
|
|
|
projectId: file.mentorAssignment.projectId,
|
|
|
|
|
roundId: params.roundId,
|
|
|
|
|
slotKey: params.slotKey,
|
|
|
|
|
sourceType: 'MENTOR_FILE',
|
|
|
|
|
sourceFileId: params.mentorFileId,
|
|
|
|
|
promotedById: params.promotedById,
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
await tx.decisionAuditLog.create({
|
|
|
|
|
data: {
|
|
|
|
|
eventType: 'mentor_file.promoted',
|
|
|
|
|
entityType: 'MentorFile',
|
|
|
|
|
entityId: params.mentorFileId,
|
|
|
|
|
actorId: params.promotedById,
|
|
|
|
|
detailsJson: {
|
|
|
|
|
projectId: file.mentorAssignment.projectId,
|
|
|
|
|
roundId: params.roundId,
|
|
|
|
|
slotKey: params.slotKey,
|
|
|
|
|
fileName: file.fileName,
|
|
|
|
|
},
|
|
|
|
|
snapshotJson: { timestamp: new Date().toISOString(), emittedBy: 'mentor-workspace' },
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
await logAudit({
|
|
|
|
|
prisma: tx,
|
|
|
|
|
userId: params.promotedById,
|
|
|
|
|
action: 'MENTOR_FILE_PROMOTE',
|
|
|
|
|
entityType: 'MentorFile',
|
|
|
|
|
entityId: params.mentorFileId,
|
|
|
|
|
detailsJson: {
|
|
|
|
|
projectId: file.mentorAssignment.projectId,
|
|
|
|
|
slotKey: params.slotKey,
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return { success: true }
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('[MentorWorkspace] promoteFile failed:', error)
|
|
|
|
|
return {
|
|
|
|
|
success: false,
|
|
|
|
|
errors: [error instanceof Error ? error.message : 'Unknown error'],
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|