MOPC-App/docs/claude-architecture-redesign/08-round-mentoring.md

500 lines
23 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Round: Mentoring (Finalist Collaboration Layer)
## 1. Purpose & Position in Flow
The MENTORING round is **not a judging stage** — it is a collaboration layer that activates between Jury 2 finalist selection and the Live Finals. It provides finalist teams who requested mentoring with a private workspace to refine their submissions with guidance from an assigned mentor.
| Aspect | Detail |
|--------|--------|
| Position | Round 6 (after Jury 2, before Live Finals) |
| Participants | Finalist teams + assigned mentors |
| Duration | Configurable (typically 2-4 weeks) |
| Output | Better-prepared finalist submissions; some mentoring files promoted to official submissions |
### Who Gets Mentoring
- Only projects that have `Project.wantsMentorship = true` AND have advanced to finalist status (ProjectRoundState PASSED in the Jury 2 round)
- Admin can override: assign mentoring to projects that didn't request it, or skip projects that did
---
## 2. Data Model
### Round Record
```
Round {
id: "round-mentoring"
competitionId: "comp-2026"
name: "Finalist Mentoring"
roundType: MENTORING
status: ROUND_DRAFT → ROUND_ACTIVE → ROUND_CLOSED
sortOrder: 5
windowOpenAt: "2026-06-01" // Mentoring period start
windowCloseAt: "2026-06-30" // Mentoring period end
juryGroupId: null // No jury for mentoring
submissionWindowId: null // Mentoring doesn't collect formal submissions
configJson: { ...MentoringConfig }
}
```
### MentoringConfig
```typescript
type MentoringConfig = {
// Who gets mentoring
eligibility: "all_advancing" | "requested_only"
// all_advancing: Every finalist gets a mentor
// requested_only: Only projects with wantsMentorship=true
// Workspace features
chatEnabled: boolean // Bidirectional messaging (default: true)
fileUploadEnabled: boolean // Mentor + team can upload files (default: true)
fileCommentsEnabled: boolean // Threaded comments on files (default: true)
filePromotionEnabled: boolean // Promote workspace file to official submission (default: true)
// Promotion target
promotionTargetWindowId: string | null
// Which SubmissionWindow promoted files go to
// Usually the most recent window (Round 2 docs)
// If null, promotion creates files without a window (admin must assign)
// Auto-assignment
autoAssignMentors: boolean // Use AI/algorithm to assign (default: false)
maxProjectsPerMentor: number // Mentor workload cap (default: 3)
// Notifications
notifyTeamsOnOpen: boolean // Email teams when mentoring opens (default: true)
notifyMentorsOnAssign: boolean // Email mentors when assigned (default: true)
reminderBeforeClose: number[] // Days before close to remind (default: [7, 3, 1])
}
```
### Related Models
| Model | Purpose |
|-------|---------|
| `MentorAssignment` | Links mentor to project (existing, enhanced) |
| `MentorMessage` | Chat messages between mentor and team (existing) |
| `MentorNote` | Mentor's private notes (existing) |
| `MentorFile` | **NEW** — Files uploaded in workspace |
| `MentorFileComment` | **NEW** — Threaded comments on files |
| `ProjectFile` | Target for file promotion |
| `SubmissionFileRequirement` | Requirement slot that promoted file fills |
---
## 3. Mentor Assignment
### 3.1 Assignment Methods
| Method | Description |
|--------|-------------|
| `MANUAL` | Admin picks mentor for each project |
| `AI_SUGGESTED` | AI recommends matches, admin approves |
| `AI_AUTO` | AI auto-assigns, admin can override |
| `ALGORITHM` | Round-robin or expertise-matching algorithm |
### 3.2 Assignment Criteria
The existing `mentor-matching.ts` service evaluates:
- **Expertise overlap** — mentor's tags vs project's tags/category
- **Country/region diversity** — avoid same-country bias
- **Workload balance** — distribute evenly across mentors
- **Language** — match if language preferences exist
### 3.3 Assignment Flow
```
1. MENTORING round opens (status → ROUND_ACTIVE)
2. System identifies eligible projects:
- All finalists (if eligibility = "all_advancing")
- Only finalists with wantsMentorship (if "requested_only")
3. For each eligible project without a mentor:
a. If autoAssignMentors: Run AI/algorithm assignment
b. Else: Flag as "needs mentor" in admin dashboard
4. Admin reviews assignments, can:
- Accept suggestions
- Reassign mentors
- Skip projects (no mentoring needed)
5. Assigned mentors receive email notification
6. Workspace becomes active for mentor+team
```
### 3.4 Workspace Activation
When a mentor is assigned and the MENTORING round is ROUND_ACTIVE:
```typescript
// MentorAssignment is updated:
{
workspaceEnabled: true,
workspaceOpenAt: round.windowOpenAt,
workspaceCloseAt: round.windowCloseAt,
}
```
The workspace is accessible from:
- **Mentor dashboard** → "My Projects" → select project → Workspace tab
- **Applicant dashboard** → "Mentor" section → Workspace tab
- **Admin** → can view any workspace at any time
---
## 4. Workspace Features
### 4.1 Messaging (Chat)
Bidirectional chat between mentor and team members:
```
┌────────────────────────────────────────────────┐
│ Mentor Workspace — OceanClean AI │
│ ──────────────────────────────────────────── │
│ [💬 Chat] [📁 Files] [📋 Milestones] │
│ │
│ ┌────────────────────────────────────────┐ │
│ │ Dr. Martin (Mentor) Apr 5, 10:30│ │
│ │ Welcome! I've reviewed your business │ │
│ │ plan. Let's work on the financial │ │
│ │ projections section. │ │
│ │ │ │
│ │ Sarah (Team Lead) Apr 5, 14:15│ │
│ │ Thank you! We've uploaded a revised │ │
│ │ version. See the Files tab. │ │
│ │ │ │
│ │ Dr. Martin (Mentor) Apr 6, 09:00│ │
│ │ Great improvement! I've left comments │ │
│ │ on the file. One more round should do. │ │
│ └────────────────────────────────────────┘ │
│ │
│ [Type a message... ] [Send] │
└────────────────────────────────────────────────┘
```
**Implementation:**
- Uses existing `MentorMessage` model
- Messages auto-marked as read when the chat is viewed
- Real-time updates via polling (every 10s) or WebSocket if available
- Both mentor and any team member can send messages
### 4.2 File Upload & Comments
The core new feature: a private file space with threaded discussion.
```
┌────────────────────────────────────────────────┐
│ [💬 Chat] [📁 Files] [📋 Milestones] │
│ │
│ ┌── Workspace Files ───────────────────────┐ │
│ │ │ │
│ │ 📄 Business Plan v2.pdf │ │
│ │ Uploaded by Sarah (Team) · Apr 5 │ │
│ │ 💬 3 comments │ │
│ │ [Download] [Comment] [Promote →] │ │
│ │ │ │
│ │ 📄 Financial Model.xlsx │ │
│ │ Uploaded by Dr. Martin (Mentor) · Apr 6│ │
│ │ 💬 1 comment │ │
│ │ [Download] [Comment] │ │
│ │ │ │
│ │ 📄 Pitch Deck Draft.pptx │ │
│ │ Uploaded by Sarah (Team) · Apr 8 │ │
│ │ ✅ Promoted → "Presentation" slot │ │
│ │ [Download] [View Comments] │ │
│ │ │ │
│ └──────────────────────────────────────────┘ │
│ │
│ [📤 Upload File] │
└────────────────────────────────────────────────┘
```
**File Upload Flow:**
1. User (mentor or team member) clicks "Upload File"
2. Client calls `mentor.getWorkspaceUploadUrl(mentorAssignmentId, fileName, mimeType)`
3. Server generates MinIO pre-signed PUT URL
4. Client uploads directly to MinIO
5. Client calls `mentor.saveWorkspaceFile(mentorAssignmentId, fileName, mimeType, size, bucket, objectKey, description)`
6. Server creates `MentorFile` record
**File Comments:**
```
┌── Comments on: Business Plan v2.pdf ──────────┐
│ │
│ Dr. Martin (Mentor) · Apr 5, 16:00 │
│ Section 3.2 needs stronger market analysis. │
│ Consider adding competitor comparisons. │
│ └─ Sarah (Team) · Apr 5, 18:30 │
│ Good point — we'll add a competitive │
│ landscape section. See updated version. │
│ │
│ Dr. Martin (Mentor) · Apr 6, 10:00 │
│ Revenue projections look much better now. │
│ Ready for promotion to official submission? │
│ └─ Sarah (Team) · Apr 6, 11:00 │
│ Yes, let's promote it! │
│ │
│ [Add comment... ] [Post] │
└────────────────────────────────────────────────┘
```
**Implementation:**
- `MentorFileComment` with `parentCommentId` for threading
- Both mentor and team members can comment
- Admin can view all comments
- Comments are timestamped and attributed
### 4.3 File Promotion to Official Submission
The key feature: converting a private mentoring file into an official submission document.
**Promotion Flow:**
```
1. Team member (or admin) clicks "Promote →" on a workspace file
2. Dialog appears:
┌────────────────────────────────────────┐
│ Promote File to Official Submission │
│ │
│ File: Business Plan v2.pdf │
│ │
│ Target submission window: │
│ [Round 2 Docs ▾] │
│ │
│ Replaces requirement: │
│ [Business Plan ▾] │
│ │
│ ⚠ This will replace the current │
│ "Business Plan" file for this project. │
│ │
│ [Cancel] [Promote & Replace] │
└────────────────────────────────────────┘
3. On confirmation:
a. System creates a new ProjectFile record:
- projectId: project's ID
- submissionWindowId: selected window
- requirementId: selected requirement slot
- fileName, mimeType, size: copied from MentorFile
- bucket, objectKey: SAME as MentorFile (no file duplication)
- version: incremented from previous file in slot
b. Previous file in that slot gets `replacedById` set to new file
c. MentorFile updated:
- isPromoted: true
- promotedToFileId: new ProjectFile ID
- promotedAt: now
- promotedByUserId: actor ID
d. Audit log entry created:
- action: "MENTOR_FILE_PROMOTED"
- details: { mentorFileId, projectFileId, submissionWindowId, requirementId, replacedFileId }
```
**Key Rules:**
- Only files in **active** mentoring workspaces can be promoted
- Promotion **replaces** the existing file for that requirement slot (per user's decision)
- The MinIO object is **not duplicated** — both MentorFile and ProjectFile point to the same objectKey
- Once promoted, the MentorFile shows a "Promoted" badge and the promote button is disabled
- Admin can un-promote (revert) if needed, which deletes the ProjectFile and resets MentorFile flags
- Promotion is audited with full provenance chain
**Who Can Promote:**
- Team lead (Project.submittedByUserId or TeamMember.role = LEAD)
- Admin (always)
- Mentor (only if `MentoringConfig.mentorCanPromote` is true — default false for safety)
### 4.4 Privacy Model
```
Visibility Matrix:
┌──────────────────┬────────┬──────────┬───────┬──────┐
│ Content │ Mentor │ Team │ Admin │ Jury │
├──────────────────┼────────┼──────────┼───────┼──────┤
│ Chat messages │ ✅ │ ✅ │ ✅ │ ❌ │
│ Workspace files │ ✅ │ ✅ │ ✅ │ ❌ │
│ File comments │ ✅ │ ✅ │ ✅ │ ❌ │
│ Mentor notes │ ✅ │ ❌ │ ✅* │ ❌ │
│ Promoted files │ ✅ │ ✅ │ ✅ │ ✅** │
└──────────────────┴────────┴──────────┴───────┴──────┘
* Only if MentorNote.isVisibleToAdmin = true
** Promoted files become official submissions visible to jury
```
---
## 5. Mentor Dashboard
```
┌──────────────────────────────────────────────────────────┐
│ Mentor Dashboard │
│ ─────────────────────────────────────────────────────── │
│ │
│ Mentoring Period: June 1 June 30 │
│ ⏱ 18 days remaining │
│ │
│ ┌─────────┐ ┌─────────┐ ┌──────────┐ │
│ │ 3 │ │ 12 │ │ 5 │ │
│ │ Teams │ │ Messages│ │ Files │ │
│ └─────────┘ └─────────┘ └──────────┘ │
│ │
│ My Assigned Teams │
│ ┌────────────────────────────────────────────────────┐ │
│ │ OceanClean AI (Startup) │ │
│ │ 💬 2 unread messages · 📁 3 files · Last: Apr 6 │ │
│ │ [Open Workspace] │ │
│ ├────────────────────────────────────────────────────┤ │
│ │ Blue Carbon Hub (Concept) │ │
│ │ 💬 0 unread · 📁 1 file · Last: Apr 4 │ │
│ │ [Open Workspace] │ │
│ ├────────────────────────────────────────────────────┤ │
│ │ SeaWatch Monitor (Startup) │ │
│ │ ⚠ No activity yet │ │
│ │ [Open Workspace] │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ Milestones │
│ ┌────────────────────────────────────────────────────┐ │
│ │ ☑ Initial review (3/3 teams) │ │
│ │ ☐ Business plan feedback (1/3 teams) │ │
│ │ ☐ Pitch deck review (0/3 teams) │ │
│ └────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘
```
---
## 6. Applicant Experience
On the applicant dashboard, a "Mentoring" section appears when mentoring is active:
```
┌────────────────────────────────────────────────┐
│ Your Mentor: Dr. Martin Duval │
│ Expertise: Marine Biology, Sustainability │
│ │
│ Mentoring Period: June 1 June 30 │
│ ⏱ 18 days remaining │
│ │
│ [💬 Messages (2 unread)] │
│ [📁 Workspace Files (3)] │
│ [📋 Milestones] │
└────────────────────────────────────────────────┘
```
Clicking "Workspace Files" opens the same workspace view as the mentor (with appropriate permissions).
---
## 7. Admin Experience
Admin can:
- **Assign/reassign mentors** via bulk or individual assignment
- **View any workspace** (read-only or with full edit access)
- **Promote files** on behalf of teams
- **Track activity** — dashboard showing mentor engagement:
- Messages sent per mentor
- Files uploaded
- Milestones completed
- Last activity timestamp
- **Extend/close mentoring window** per team or globally
- **Export workspace data** for audit purposes
---
## 8. API — New and Modified Procedures
### New Procedures (mentor-workspace router)
| Procedure | Auth | Purpose |
|-----------|------|---------|
| `mentorWorkspace.getUploadUrl` | Mentor or Team | Get MinIO pre-signed URL for workspace upload |
| `mentorWorkspace.saveFile` | Mentor or Team | Create MentorFile record after upload |
| `mentorWorkspace.listFiles` | Mentor, Team, Admin | List workspace files with comment counts |
| `mentorWorkspace.deleteFile` | Uploader or Admin | Delete workspace file |
| `mentorWorkspace.getFileDownloadUrl` | Mentor, Team, Admin | Get MinIO pre-signed URL for download |
| `mentorWorkspace.addComment` | Mentor, Team, Admin | Add comment to file (with optional parentCommentId) |
| `mentorWorkspace.listComments` | Mentor, Team, Admin | Get threaded comments for a file |
| `mentorWorkspace.deleteComment` | Author or Admin | Delete a comment |
| `mentorWorkspace.promoteFile` | Team Lead or Admin | Promote workspace file to official submission |
| `mentorWorkspace.unpromoteFile` | Admin only | Revert a promotion |
| `mentorWorkspace.getWorkspaceStatus` | Any participant | Get workspace summary (file count, message count, etc.) |
### Modified Existing Procedures
| Procedure | Change |
|-----------|--------|
| `mentor.getMyProjects` | Include workspace status (file count, unread messages) |
| `mentor.getProjectDetail` | Include MentorFile[] with comment counts |
| `applicant.getMyDashboard` | Include mentor workspace summary if mentoring active |
| `file.listByProjectForRound` | Promoted files visible to jury (via ProjectFile record) |
---
## 9. Service: `mentor-workspace.ts`
### Key Functions
```typescript
// Upload handling
async function getWorkspaceUploadUrl(
mentorAssignmentId: string,
fileName: string,
mimeType: string,
actorId: string,
prisma: PrismaClient
): Promise<{ uploadUrl: string; objectKey: string }>
// Save file metadata after upload
async function saveWorkspaceFile(
mentorAssignmentId: string,
uploadedByUserId: string,
file: { fileName, mimeType, size, bucket, objectKey },
description: string | null,
prisma: PrismaClient
): Promise<MentorFile>
// Promote file to official submission
async function promoteFileToSubmission(
mentorFileId: string,
submissionWindowId: string,
requirementId: string | null,
actorId: string,
prisma: PrismaClient
): Promise<{ mentorFile: MentorFile; projectFile: ProjectFile }>
// Steps:
// 1. Validate mentorFile exists, is not already promoted, workspace is active
// 2. If requirementId: find existing ProjectFile for that requirement, set replacedById
// 3. Create new ProjectFile (reusing same bucket/objectKey — no MinIO duplication)
// 4. Update MentorFile: isPromoted=true, promotedToFileId, promotedAt, promotedByUserId
// 5. Audit log with full provenance
// Revert promotion
async function unpromoteFile(
mentorFileId: string,
actorId: string,
prisma: PrismaClient
): Promise<void>
// Steps:
// 1. Find the ProjectFile created by promotion
// 2. If it replaced a previous file, restore that file's replacedById=null
// 3. Delete the promoted ProjectFile
// 4. Reset MentorFile flags
// 5. Audit log
```
---
## 10. Edge Cases
| Scenario | Handling |
|----------|----------|
| Team doesn't want mentoring but admin assigns anyway | Assignment created; team sees mentor in dashboard |
| Mentor goes inactive during period | Admin can reassign; previous workspace preserved |
| File promoted then mentor period closes | Promoted file remains as official submission |
| Team tries to promote file for a requirement that doesn't exist | Error — must select valid requirement or leave requirementId null |
| Two files promoted to the same requirement slot | Second promotion replaces first (versioning) |
| Mentoring file is larger than requirement maxSizeMB | Warning shown but promotion allowed (admin override implicit) |
| Workspace closed but team needs one more upload | Admin can extend via round window or grant grace |
| Promoted file deleted from workspace | ProjectFile remains (separate record); audit shows provenance |