# Mentoring & Document Lifecycle ## Overview This document covers two interconnected systems: (1) the multi-round document lifecycle that governs how submissions flow through the competition, and (2) the mentoring workspace that provides a collaboration layer for finalist teams with assigned mentors. --- ## Part 1: Document Lifecycle ### SubmissionWindow Each round that requires document collection has an associated `SubmissionWindow`. A competition can have multiple windows (e.g., Round 1 application docs, Round 2 semifinal docs). ```prisma model SubmissionWindow { id String @id @default(cuid()) competitionId String roundId String label String // "Round 1 Application Documents", "Round 2 Semifinal Documents" opensAt DateTime closesAt DateTime deadlinePolicy DeadlinePolicy @default(HARD) gracePeriodMinutes Int? // only used with GRACE policy lockOnClose Boolean @default(true) // automatically lock submissions when window closes isLocked Boolean @default(false) // manual lock toggle (admin can lock before close) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt competition Competition @relation(...) round Round @relation(...) requirements SubmissionFileRequirement[] @@index([competitionId]) @@index([roundId]) } ``` ### DeadlinePolicy | Policy | Behavior | |--------|----------| | `HARD` | Submissions are cut off at `closesAt`. No uploads after the deadline. | | `FLAG` | Submissions after `closesAt` are accepted but marked as **Late**. Admin can see late status. | | `GRACE` | A grace period (`gracePeriodMinutes`) after `closesAt` during which submissions are still accepted without penalty. After grace, behaves as HARD. | ```prisma enum DeadlinePolicy { HARD FLAG GRACE } ``` ### SubmissionFileRequirement Each window defines required file slots: ```prisma model SubmissionFileRequirement { id String @id @default(cuid()) submissionWindowId String slotKey String // "executive_summary", "business_plan", "pitch_video" label String // "Executive Summary" description String? // guidance text for applicants required Boolean @default(true) maxFileSize Int @default(10485760) // 10MB default acceptedTypes String[] // ["application/pdf", "video/mp4"] sortOrder Int @default(0) submissionWindow SubmissionWindow @relation(...) @@unique([submissionWindowId, slotKey]) } ``` ### Multi-Round Document Visibility | Actor | Current Round Docs | Previous Round Docs | |-------|-------------------|-------------------| | **Applicant** | Can upload/edit until window closes | **Read-only** (view/download only) | | **Judge** | Sees current round docs in review | Sees previous round docs (clearly separated in UI) | | **Admin** | Full control (upload/remove/replace) | Full control (upload/remove/replace) | | **Mentor** | Sees within mentor workspace | Sees within mentor workspace | When a submission window closes or a round advances: - Applicant's editing permissions for that window's docs are revoked - Docs remain visible for download - Judges in subsequent rounds can view all prior docs ### RoundSubmissionVisibility Controls which prior round docs are visible to judges: ```prisma model RoundSubmissionVisibility { id String @id @default(cuid()) roundId String // the round where the judge is reviewing visibleRoundId String // the round whose docs are visible separateInUi Boolean @default(true) // show in separate section round Round @relation("reviewingRound", ...) visibleRound Round @relation("visibleRound", ...) @@unique([roundId, visibleRoundId]) } ``` For example, Jury 2 (R5) would have visibility entries for R1 (Intake docs) and R4 (Semifinal docs), both with `separateInUi: true`. --- ## Part 2: Mentoring Workspace ### Purpose Mentoring is NOT a judging stage. It's a collaboration layer for finalist teams who have requested mentoring. Mentors help teams polish their submissions before live finals. ### Who Gets Mentoring - Only finalist teams (or whatever stage admin configures) that have "requested mentor" enabled - Mentor assignment works similarly to judge assignment (from a mentor pool) - Each mentored team gets one assigned mentor ### Workspace Features The mentor-team workspace provides three capabilities: #### 1. Messaging / Chat ```prisma model MentorMessage { id String @id @default(cuid()) projectId String // the mentored project mentorId String // the assigned mentor senderId String // who sent the message senderRole MentorMessageRole content String @db.Text createdAt DateTime @default(now()) project Project @relation(...) mentor User @relation("mentorMessages", ...) sender User @relation("sentMentorMessages", ...) @@index([projectId, mentorId]) } enum MentorMessageRole { MENTOR APPLICANT ADMIN } ``` Messaging allows real-time communication between mentor and team. Admins can also send messages into the workspace. #### 2. File Upload ```prisma model MentorFile { id String @id @default(cuid()) projectId String mentorId String uploadedById String uploaderRole MentorMessageRole fileName String fileKey String // MinIO storage key fileSize Int mimeType String description String? // Promotion tracking promotedToSlot String? // slotKey if promoted to official submission promotedAt DateTime? promotedById String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt project Project @relation(...) comments MentorFileComment[] @@index([projectId, mentorId]) } ``` Both mentor and team can upload files. Files are stored in MinIO and accessed via pre-signed URLs. #### 3. Threaded File Comments ```prisma model MentorFileComment { id String @id @default(cuid()) fileId String authorId String authorRole MentorMessageRole content String @db.Text parentId String? // for threading createdAt DateTime @default(now()) file MentorFile @relation(...) author User @relation(...) parent MentorFileComment? @relation("commentThread", ...) replies MentorFileComment[] @relation("commentThread") @@index([fileId]) } ``` Comments are threaded (parentId for replies). Each comment is tied to a specific file. ### Privacy All mentoring workspace content is **private by default**: - Visible to: the assigned mentor, the team members, and admins - NOT visible to: other teams, other mentors, judges, audience ### File Promotion to Official Submission A mentoring file can be "promoted" to become an official submission for a required document slot in the active submission round. **Example flow:** 1. Team uploads "Business Plan Draft v3.pdf" to mentor workspace 2. Mentor reviews and approves 3. Team (or admin) marks it as the official "Business Plan" submission for Round 2 4. System creates a `SubmissionPromotionEvent` with immutable provenance ```prisma model SubmissionPromotionEvent { id String @id @default(cuid()) projectId String roundId String slotKey String // the doc slot being filled sourceType PromotionSourceType sourceFileId String // MentorFile.id or admin-uploaded file ID promotedById String // who triggered the promotion createdAt DateTime @default(now()) project Project @relation(...) round Round @relation(...) promotedBy User @relation(...) @@index([projectId, roundId]) } enum PromotionSourceType { MENTOR_FILE // promoted from mentor workspace ADMIN_REPLACEMENT // admin replaced the file directly } ``` **Promotion authority:** - **Team lead**: can promote their own mentor workspace files - **Admin**: can promote any file or directly replace with admin-uploaded file - **Mentor**: can promote IF admin enables this per competition (configurable) **Provenance:** Every promotion records who promoted, when, from which source file, and the source type. This audit trail is immutable. ### MentoringConfig (Round Type Configuration) ```typescript const MentoringConfig = z.object({ eligibility: z.enum(['FINALISTS_ONLY', 'SEMIFINALISTS_AND_ABOVE', 'CONFIGURABLE']), requireMentorRequest: z.boolean().default(true), // team must opt-in assignmentMethod: z.enum(['MANUAL', 'AI_SUGGESTED', 'AI_AUTO', 'ALGORITHM']), workspaceFeatures: z.object({ messagingEnabled: z.boolean().default(true), fileUploadEnabled: z.boolean().default(true), fileCommentsEnabled: z.boolean().default(true), }), promotionTarget: z.string().optional(), // roundId where promoted files go allowMentorPromotion: z.boolean().default(false), // can mentors promote files? deadlinePolicy: z.nativeEnum(DeadlinePolicy).default('FLAG'), }) ``` ### Mentor Dashboard Mentors have a dedicated dashboard showing: - **Assigned teams**: list of all teams they're mentoring - **Per-team workspace**: click through to messaging, file exchange, comments - **Deadline tracking**: upcoming deadlines for the mentored teams - **Progress indicators**: which teams have submitted their required docs, which are pending - **File review queue**: files uploaded by teams that need mentor review See [08-platform-integration-matrix.md](./08-platform-integration-matrix.md) for the full mentor page mapping. --- ## Admin Document Controls Admins have full control over documents across all rounds: | Action | Scope | Audit | |--------|-------|-------| | View any submission | All rounds, all projects | Read-only, no audit needed | | Upload file for a project | Any round, any slot | Logged with `sourceType: ADMIN_REPLACEMENT` | | Remove/replace a file | Any round, any slot | Logged with previous file reference | | Lock a submission window early | Specific window | Logged | | Extend a deadline | Specific window | Logged | | Promote a mentor file | Any project's workspace | Creates `SubmissionPromotionEvent` | --- ## Integration Points - **R1 (Intake)**: First `SubmissionWindow` with R1 document requirements - **R4 (Semifinal Submission)**: Second `SubmissionWindow` with R2 requirements; R1 docs locked for applicants - **R5 (Jury 2)**: Judges see R1 + R2 docs clearly separated via `RoundSubmissionVisibility` - **R6 (Mentoring)**: Mentor workspace active, file promotion targets the active submission window - **R7 (Live Finals)**: Jury 3 sees all submitted docs from all rounds See [03-competition-flow.md](./03-competition-flow.md) for the complete round-by-round specification.