316 lines
10 KiB
Markdown
316 lines
10 KiB
Markdown
|
|
# 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.
|