# Integration Map: Cross-Reference Documentation ## Overview This document provides a comprehensive cross-reference of every connection between models, services, routers, and UI pages in the MOPC architecture redesign. It serves as the master integration reference for understanding how features connect across the system. **Purpose**: This is the single source of truth for: - Which services operate on which models - Which routers call which services - Which UI pages call which routers - Which features activate per round type - How data flows through the system - What notifications are triggered by which events - Where audit trails are created - What permissions control which operations --- ## 1. Model → Service Map Comprehensive mapping of every model to every service that operates on it. ### Competition Model | Service | Operations | Purpose | |---------|-----------|---------| | `competition.ts` | create, read, update, delete, list, clone | Core CRUD operations | | `round-engine.ts` | getCompetitionRounds, getActiveRounds | Round lifecycle management | | `competition-wizard.ts` | buildFromTemplate, validateConfig | Wizard-based creation | | `notification-scheduler.ts` | scheduleDeadlineReminders | Deadline countdown notifications | | `audit-service.ts` | logCompetitionCreated, logCompetitionStatusChange | Audit trail | ### Round Model | Service | Operations | Purpose | |---------|-----------|---------| | `round-engine.ts` | create, open, close, advance, rollback | State machine control | | `round-config-validator.ts` | validateConfig, validateTransition | Type-specific validation | | `assignment-orchestrator.ts` | getAssignableRounds, validateAssignmentRules | Assignment coordination | | `filtering-service.ts` | runFilteringJob, processRound | AI screening (FILTERING rounds) | | `live-control.ts` | initializeStageManager, advanceCursor | Stage manager (LIVE_FINAL rounds) | | `mentor-workspace.ts` | activateWorkspace, closeWorkspace | Workspace activation (MENTORING rounds) | | `winner-proposal.ts` | generateProposal, freezeResults | Confirmation logic (CONFIRMATION rounds) | | `notification-service.ts` | notifyRoundOpen, notifyRoundClose, notifyDeadlineApproaching | Round lifecycle notifications | ### JuryGroup Model | Service | Operations | Purpose | |---------|-----------|---------| | `jury-group.ts` | create, addMember, removeMember, updateMemberConfig, delete | Jury management | | `assignment-algorithm.ts` | getJuryGroupMembers, applyCapRules, applyQuotaRules | Assignment algorithm input | | `assignment-orchestrator.ts` | generateAssignmentsForJuryGroup, validateAssignmentCaps | Assignment coordination | | `jury-onboarding.ts` | notifyOnboardingRequired, collectPreferences | Juror onboarding | | `notification-service.ts` | notifyJuryGroupAssigned, notifyJuryDeadline | Jury-specific notifications | ### SubmissionWindow Model | Service | Operations | Purpose | |---------|-----------|---------| | `submission-window.ts` | create, open, close, lock, validateSubmission | Window lifecycle | | `file-upload-service.ts` | validateFileRequirement, checkDeadline | File upload validation | | `deadline-service.ts` | applyGracePeriod, checkDeadlinePolicy | Deadline enforcement | | `notification-service.ts` | notifyWindowOpen, notifyWindowClosing, notifyWindowClosed | Window notifications | ### ProjectRoundState Model | Service | Operations | Purpose | |---------|-----------|---------| | `round-engine.ts` | enterRound, exitRound, transitionState, bulkTransition | Project state transitions | | `advancement-service.ts` | evaluateAdvancement, applyAdvancementRule | Advancement logic | | `filtering-service.ts` | updateFilteringState | Filtering results | | `evaluation-service.ts` | updateEvaluationState | Evaluation completion | ### Assignment Model | Service | Operations | Purpose | |---------|-----------|---------| | `assignment-algorithm.ts` | generateAssignments, applyConstraints | AI/algorithm generation | | `assignment-orchestrator.ts` | create, override, delete, bulkDelete | Assignment CRUD + orchestration | | `coi-service.ts` | excludeConflicts, validateCOI | Conflict of interest enforcement | | `evaluation-service.ts` | getAssignedProjects, markComplete | Evaluation workflow | | `notification-service.ts` | notifyJuryAssignment | Assignment notifications | ### Evaluation Model | Service | Operations | Purpose | |---------|-----------|---------| | `evaluation.ts` | create, update, submit, delete | Evaluation CRUD | | `evaluation-summary.ts` | generateSummary | AI summary generation | | `peer-review.ts` | getAnonymizedReviews, compareScores | Peer review features | | `advancement-service.ts` | calculateScores, rankProjects | Advancement input | ### MentorAssignment Model | Service | Operations | Purpose | |---------|-----------|---------| | `mentor-assignment.ts` | create, update, delete, autoAssign | Mentor assignment | | `mentor-workspace.ts` | activateWorkspace, uploadFile, addComment, promoteFile | Workspace operations | | `ai-mentor-matching.ts` | suggestMatches, scoreExpertise | AI matching | | `notification-service.ts` | notifyMentorAssigned, notifyWorkspaceActivated | Mentor notifications | ### MentorFile Model | Service | Operations | Purpose | |---------|-----------|---------| | `mentor-workspace.ts` | upload, download, delete, promoteToSubmission | File operations | | `file-comment-service.ts` | addComment, replyToComment, deleteComment | Threading + comments | | `minio-service.ts` | uploadToMinio, generatePresignedUrl | MinIO integration | ### SpecialAward Model | Service | Operations | Purpose | |---------|-----------|---------| | `special-award.ts` | create, update, delete, startVoting, closeVoting | Award lifecycle | | `award-eligibility.ts` | calculateEligibility, applyAIFiltering, overrideEligibility | Eligibility determination | | `award-voting.ts` | submitVote, tallyVotes, selectWinner | Voting + results | | `notification-service.ts` | notifyAwardVotingOpen, notifyAwardWinner | Award notifications | ### WinnerProposal Model | Service | Operations | Purpose | |---------|-----------|---------| | `winner-proposal.ts` | create, requestApprovals, freeze, override | Confirmation workflow | | `winner-approval.ts` | submitApproval, checkConsensus | Approval tracking | | `audit-service.ts` | logProposal, logApproval, logOverride, logFreeze | Audit trail | | `notification-service.ts` | notifyApprovalRequested, notifyProposalApproved | Winner notifications | ### ProjectFile Model | Service | Operations | Purpose | |---------|-----------|---------| | `file-upload-service.ts` | upload, replace, delete, validateRequirement | File management | | `minio-service.ts` | uploadToMinio, deleteFromMinio, generatePresignedUrl | Storage backend | | `submission-window.ts` | validateSubmission, checkRequirements | Submission validation | ### FilteringRule & FilteringResult Models | Service | Operations | Purpose | |---------|-----------|---------| | `filtering-service.ts` | applyRules, runAIFiltering, generateResults | Filtering execution | | `duplicate-detection.ts` | detectDuplicates, scoreSimilarity | Duplicate detection | | `audit-service.ts` | logFilteringDecision, logOverride | Audit trail | ### LiveVotingSession & LiveVote Models | Service | Operations | Purpose | |---------|-----------|---------| | `live-control.ts` | startSession, submitVote, endSession, tallyResults | Live voting | | `audience-voting.ts` | registerAudience, submitAudienceVote | Audience participation | | `websocket-service.ts` | broadcastVote, syncCursor | Real-time sync | ### InAppNotification Model | Service | Operations | Purpose | |---------|-----------|---------| | `notification-service.ts` | create, markRead, delete, listUnread | In-app notifications | | `notification-scheduler.ts` | scheduleReminder, scheduleDeadline | Scheduled notifications | ### DecisionAuditLog Model | Service | Operations | Purpose | |---------|-----------|---------| | `audit-service.ts` | log (all decisions), query, export | Comprehensive audit trail | --- ## 2. Service → Router Map Which tRPC routers call which services. ### `competition.ts` Router ```typescript // Calls: - competition.ts service // CRUD operations - round-engine.ts service // getCompetitionRounds - competition-wizard.ts service // buildFromTemplate - notification-scheduler.ts // scheduleDeadlineReminders - audit-service.ts // logCompetitionCreated, logStatusChange // Procedures: - create → competition.create + audit.log + scheduler.schedule - getById → competition.getById - list → competition.list - update → competition.update + audit.log - delete → competition.delete + audit.log - getRounds → round-engine.getCompetitionRounds - buildFromWizard → competition-wizard.buildFromTemplate + audit.log ``` ### `round.ts` Router ```typescript // Calls: - round-engine.ts // All lifecycle operations - round-config-validator.ts // validateConfig - notification-service.ts // Round notifications - audit-service.ts // All round changes // Procedures: - create → round-engine.create + validator.validate + audit.log - getById → round-engine.getById - list → round-engine.list - update → round-engine.update + validator.validate + audit.log - delete → round-engine.delete + audit.log - open → round-engine.open + notification.notifyRoundOpen + audit.log - close → round-engine.close + notification.notifyRoundClose + audit.log - advance → round-engine.advance + audit.log - rollback → round-engine.rollback + audit.log ``` ### `jury-group.ts` Router ```typescript // Calls: - jury-group.ts service // CRUD - jury-onboarding.ts // Onboarding - assignment-orchestrator.ts // Assignment coordination - notification-service.ts // Notifications - audit-service.ts // Audit // Procedures: - create → jury-group.create + audit.log - addMember → jury-group.addMember + onboarding.notify + audit.log - removeMember → jury-group.removeMember + audit.log - updateMemberConfig → jury-group.updateMemberConfig + audit.log - getById → jury-group.getById - list → jury-group.list - getMembers → jury-group.getMembers ``` ### `assignment.ts` Router ```typescript // Calls: - assignment-algorithm.ts // AI/algorithm generation - assignment-orchestrator.ts // Orchestration - coi-service.ts // COI enforcement - notification-service.ts // Assignment notifications - audit-service.ts // Audit trail // Procedures: - generate → assignment-algorithm.generate + coi.excludeConflicts + orchestrator.create + notification.notify + audit.log - override → orchestrator.override + audit.log - delete → orchestrator.delete + audit.log - bulkDelete → orchestrator.bulkDelete + audit.log - getByRound → orchestrator.getByRound - getByJuror → orchestrator.getByJuror ``` ### `evaluation.ts` Router ```typescript // Calls: - evaluation.ts service // CRUD - evaluation-summary.ts // AI summaries - peer-review.ts // Peer review - advancement-service.ts // Advancement - notification-service.ts // Notifications - audit-service.ts // Audit // Procedures: - getAssignment → evaluation.getAssignment + coi.check - submit → evaluation.submit + advancement.check + notification.notifyComplete + audit.log - update → evaluation.update + audit.log - getSummary → evaluation-summary.generate - getPeerReviews → peer-review.getAnonymized ``` ### `filtering.ts` Router ```typescript // Calls: - filtering-service.ts // Core filtering - duplicate-detection.ts // Duplicate detection - ai-filtering.ts // AI screening - notification-service.ts // Notifications - audit-service.ts // Audit // Procedures: - runJob → filtering-service.runFilteringJob + ai-filtering.screen + duplicate-detection.detect + notification.notify + audit.log - getResults → filtering-service.getResults - override → filtering-service.override + audit.log - getDuplicates → duplicate-detection.getDuplicates ``` ### `submission-window.ts` Router ```typescript // Calls: - submission-window.ts service // Lifecycle - file-upload-service.ts // File handling - deadline-service.ts // Deadline enforcement - notification-service.ts // Notifications - audit-service.ts // Audit // Procedures: - create → submission-window.create + audit.log - open → submission-window.open + notification.notifyWindowOpen + audit.log - close → submission-window.close + notification.notifyWindowClosed + audit.log - lock → submission-window.lock + audit.log - uploadFile → file-upload.upload + deadline.check + audit.log - getFiles → submission-window.getFiles ``` ### `mentor-workspace.ts` Router ```typescript // Calls: - mentor-workspace.ts service // Workspace operations - file-comment-service.ts // Comments - mentor-assignment.ts // Assignment - notification-service.ts // Notifications - audit-service.ts // Audit // Procedures: - activateWorkspace → mentor-workspace.activate + notification.notify + audit.log - uploadFile → mentor-workspace.uploadFile + audit.log - addComment → file-comment.addComment + notification.notify - promoteFile → mentor-workspace.promoteToSubmission + audit.log + notification.notify - getFiles → mentor-workspace.getFiles ``` ### `special-award.ts` Router ```typescript // Calls: - special-award.ts service // Award lifecycle - award-eligibility.ts // Eligibility - award-voting.ts // Voting - notification-service.ts // Notifications - audit-service.ts // Audit // Procedures: - create → special-award.create + audit.log - updateEligibility → award-eligibility.calculate + audit.log - startVoting → special-award.startVoting + notification.notifyVotingOpen + audit.log - submitVote → award-voting.submitVote + audit.log - closeVoting → special-award.closeVoting + award-voting.tallyVotes + notification.notifyWinner + audit.log ``` ### `winner-proposal.ts` Router ```typescript // Calls: - winner-proposal.ts service // Proposal lifecycle - winner-approval.ts // Approvals - notification-service.ts // Notifications - audit-service.ts // Audit // Procedures: - create → winner-proposal.create + winner-approval.requestApprovals + notification.notifyApprovalRequested + audit.log - submitApproval → winner-approval.submitApproval + winner-approval.checkConsensus + notification.notify + audit.log - override → winner-proposal.override + audit.log - freeze → winner-proposal.freeze + audit.log + notification.notifyFrozen ``` ### `live-control.ts` Router ```typescript // Calls: - live-control.ts service // Stage manager - audience-voting.ts // Audience - websocket-service.ts // Real-time sync - notification-service.ts // Notifications - audit-service.ts // Audit // Procedures: - initStageManager → live-control.initialize + audit.log - advanceCursor → live-control.advanceCursor + websocket.broadcast + audit.log - startVoting → live-control.startVoting + notification.notify + audit.log - submitJuryVote → live-control.submitVote + websocket.broadcast + audit.log - submitAudienceVote → audience-voting.submit + websocket.broadcast - endVoting → live-control.endVoting + live-control.tallyResults + audit.log ``` --- ## 3. Router → UI Page Map Which UI pages call which tRPC routers. ### Admin UI Pages #### `/admin/competition/[id]` (Competition Detail) ```typescript // Calls: trpc.competition.getById // Load competition trpc.competition.update // Update settings trpc.competition.delete // Delete competition trpc.round.list // List rounds trpc.juryGroup.list // List juries trpc.submissionWindow.list // List submission windows trpc.specialAward.list // List awards ``` #### `/admin/competition/[id]/wizard` (Competition Wizard) ```typescript // Calls: trpc.competition.buildFromWizard // Create from template trpc.round.create // Create rounds trpc.juryGroup.create // Create juries trpc.submissionWindow.create // Create windows ``` #### `/admin/competition/[id]/round/[roundId]` (Round Detail) ```typescript // Calls: trpc.round.getById // Load round trpc.round.update // Update config trpc.round.open // Open round trpc.round.close // Close round trpc.assignment.getByRound // View assignments trpc.filtering.getResults // View filtering results (FILTERING) trpc.evaluation.list // View evaluations (EVALUATION) trpc.liveControl.initStageManager // Stage manager (LIVE_FINAL) trpc.winnerProposal.getByRound // View proposals (CONFIRMATION) ``` #### `/admin/jury-group/[id]` (Jury Group Management) ```typescript // Calls: trpc.juryGroup.getById // Load jury trpc.juryGroup.addMember // Add juror trpc.juryGroup.removeMember // Remove juror trpc.juryGroup.updateMemberConfig // Update caps/quotas trpc.assignment.generate // Generate assignments ``` #### `/admin/assignment/[roundId]` (Assignment Manager) ```typescript // Calls: trpc.assignment.generate // AI/algorithm generation trpc.assignment.getByRound // View assignments trpc.assignment.override // Override assignment trpc.assignment.delete // Remove assignment trpc.assignment.bulkDelete // Bulk remove ``` #### `/admin/filtering/[roundId]` (Filtering Dashboard) ```typescript // Calls: trpc.filtering.runJob // Start filtering trpc.filtering.getResults // View results trpc.filtering.override // Override AI decision trpc.filtering.getDuplicates // View duplicates ``` #### `/admin/live-control/[roundId]` (Stage Manager) ```typescript // Calls: trpc.liveControl.initStageManager // Initialize trpc.liveControl.advanceCursor // Advance project trpc.liveControl.startVoting // Start vote trpc.liveControl.endVoting // End vote // + WebSocket subscriptions for real-time updates ``` #### `/admin/winner-confirmation/[competitionId]` (Winner Confirmation) ```typescript // Calls: trpc.winnerProposal.getByCompetition // Load proposals trpc.winnerProposal.create // Create proposal trpc.winnerProposal.override // Override result trpc.winnerProposal.freeze // Freeze result trpc.winnerApproval.list // View approvals ``` #### `/admin/award/[awardId]` (Special Award Manager) ```typescript // Calls: trpc.specialAward.getById // Load award trpc.specialAward.updateEligibility // Update eligible projects trpc.specialAward.startVoting // Open voting trpc.specialAward.getVotes // View votes trpc.specialAward.closeVoting // Close + tally ``` ### Jury UI Pages #### `/jury/dashboard` (Jury Dashboard) ```typescript // Calls: trpc.juryGroup.getMyGroups // Which juries am I in trpc.assignment.getByJuror // My assignments trpc.round.getActive // Active rounds trpc.evaluation.getMyEvaluations // My evaluations ``` #### `/jury/evaluate/[projectId]` (Evaluation Form) ```typescript // Calls: trpc.evaluation.getAssignment // Load assignment trpc.project.getById // Load project details trpc.projectFile.list // Load files (multi-round) trpc.evaluation.submit // Submit evaluation trpc.coi.declare // Declare COI trpc.peerReview.getAnonymized // View peer reviews ``` #### `/jury/live-finals` (Live Voting Interface) ```typescript // Calls: trpc.liveControl.getSession // Current session trpc.liveVote.submit // Submit vote // + WebSocket subscriptions for cursor, votes ``` #### `/jury/confirm-winners/[proposalId]` (Winner Approval) ```typescript // Calls: trpc.winnerProposal.getById // Load proposal trpc.winnerApproval.submit // Approve/reject ``` ### Applicant UI Pages #### `/applicant/dashboard` (Applicant Dashboard) ```typescript // Calls: trpc.project.getMyProjects // My projects trpc.submissionWindow.getActive // Active windows trpc.projectRoundState.getByProject // Round statuses trpc.mentorAssignment.getByProject // Mentor info ``` #### `/applicant/submit/[windowId]` (Submission Form) ```typescript // Calls: trpc.submissionWindow.getById // Window details trpc.fileRequirement.list // Required files trpc.projectFile.upload // Upload file trpc.project.submitApplication // Submit ``` #### `/applicant/project/[projectId]` (Project Detail) ```typescript // Calls: trpc.project.getById // Project details trpc.projectFile.list // All files (multi-round) trpc.projectRoundState.list // Round history trpc.evaluation.getSummary // Feedback (if released) ``` #### `/applicant/mentoring/[projectId]` (Mentoring Workspace) ```typescript // Calls: trpc.mentorWorkspace.getFiles // Workspace files trpc.mentorWorkspace.uploadFile // Upload file trpc.mentorWorkspace.addComment // Comment on file trpc.mentorMessage.list // Messages trpc.mentorMessage.send // Send message ``` ### Mentor UI Pages #### `/mentor/dashboard` (Mentor Dashboard) ```typescript // Calls: trpc.mentorAssignment.getMyAssignments // My teams trpc.mentorWorkspace.getActiveWorkspaces // Active workspaces ``` #### `/mentor/workspace/[assignmentId]` (Mentor Workspace) ```typescript // Calls: trpc.mentorWorkspace.getFiles // Workspace files trpc.mentorWorkspace.uploadFile // Upload file trpc.mentorWorkspace.addComment // Comment on file trpc.mentorWorkspace.promoteFile // Promote to submission trpc.mentorMessage.list // Messages trpc.mentorMessage.send // Send message ``` --- ## 4. Round Type → Feature Matrix Which features are active for each round type. | Feature | INTAKE | FILTERING | EVALUATION | SUBMISSION | MENTORING | LIVE_FINAL | CONFIRMATION | |---------|--------|-----------|------------|------------|-----------|------------|--------------| | **Submission Window** | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | ✗ | | **File Requirements** | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | ✗ | | **Deadline Policy** | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | ✗ | | **Draft Saving** | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | ✗ | | **Applicant Forms** | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | ✗ | | **Jury Group** | ✗ | ✗ | ✓ | ✗ | ✗ | ✓ | ✓ (approval) | | **Assignment Algorithm** | ✗ | ✗ | ✓ | ✗ | ✗ | ✗ | ✗ | | **Assignment Caps** | ✗ | ✗ | ✓ | ✗ | ✗ | ✗ | ✗ | | **Category Quotas** | ✗ | ✗ | ✓ | ✗ | ✗ | ✗ | ✗ | | **COI Declaration** | ✗ | ✗ | ✓ | ✗ | ✗ | ✓ | ✗ | | **Evaluation Form** | ✗ | ✗ | ✓ | ✗ | ✗ | ✗ | ✗ | | **Scoring (Criteria)** | ✗ | ✗ | ✓ | ✗ | ✗ | ✓ (optional) | ✗ | | **Scoring (Global)** | ✗ | ✗ | ✓ | ✗ | ✗ | ✓ | ✗ | | **Binary Decision** | ✗ | ✓ (AI) | ✓ (optional) | ✗ | ✗ | ✗ | ✗ | | **Feedback** | ✗ | ✗ | ✓ | ✗ | ✗ | ✗ | ✗ | | **Peer Review** | ✗ | ✗ | ✓ | ✗ | ✗ | ✗ | ✗ | | **AI Summary** | ✗ | ✗ | ✓ | ✗ | ✗ | ✗ | ✗ | | **Advancement Rules** | ✗ | ✓ | ✓ | ✗ | ✗ | ✓ | ✗ | | **Top-N Selection** | ✗ | ✓ | ✓ | ✗ | ✗ | ✓ | ✗ | | **AI Filtering** | ✗ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **Duplicate Detection** | ✗ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **Filtering Rules** | ✗ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **Admin Override** | ✗ | ✓ | ✓ | ✗ | ✗ | ✓ | ✓ | | **Mentor Assignment** | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ | ✗ | | **Mentor Workspace** | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ | ✗ | | **Workspace Files** | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ | ✗ | | **File Comments** | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ | ✗ | | **File Promotion** | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ | ✗ | | **Mentor Messages** | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ | ✗ | | **Stage Manager** | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ | | **Live Cursor** | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ | | **Jury Voting** | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ | | **Audience Voting** | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ (optional) | ✗ | | **Deliberation Period** | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ (optional) | ✗ | | **WebSocket Sync** | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ | | **Winner Proposal** | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | | **Jury Approval** | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | | **Admin Freeze** | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | | **Override Mode** | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | | **Multi-Window Visibility** | ✗ | ✗ | ✓ | ✗ | ✗ | ✓ | ✗ | | **Grace Period** | ✓ (optional) | ✗ | ✗ | ✓ (optional) | ✗ | ✗ | ✗ | | **Late Flag** | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | ✗ | --- ## 5. Data Flow Diagrams ### 5.1 Application Submission Flow (INTAKE) ``` Applicant | | 1. Visit /applicant/submit/[windowId] | v UI: Check active SubmissionWindow | trpc.submissionWindow.getActive v Backend: submission-window.ts | Query: SubmissionWindow where windowOpenAt <= now <= windowCloseAt v UI: Load FileRequirements | trpc.fileRequirement.list v Backend: submission-window.ts | Query: SubmissionFileRequirement where submissionWindowId v UI: Upload files | trpc.projectFile.upload (per requirement) v Backend: file-upload-service.ts | | 1. Validate requirement (mime type, size) | 2. Check deadline (deadline-service.ts) | - Apply grace period if configured | - Set isLate flag if past deadline | 3. Upload to MinIO (minio-service.ts) | 4. Create ProjectFile record | - Links to submissionWindowId, requirementId | 5. Audit log (audit-service.ts) v Database: ProjectFile record created | v UI: Submit application | trpc.project.submit v Backend: project.ts | | 1. Validate all required files uploaded | 2. Create ProjectRoundState (roundId = INTAKE round, state = IN_PROGRESS) | 3. Notification (notification-service.ts) | - Send confirmation email to applicant | 4. Audit log v Database: ProjectRoundState created | v Applicant receives confirmation notification ``` ### 5.2 Filtering Flow (FILTERING) ``` Admin | | 1. Visit /admin/filtering/[roundId] | v UI: Start filtering job | trpc.filtering.runJob v Backend: filtering-service.ts | | 1. Create FilteringJob record (status: RUNNING) | 2. Get all projects in INTAKE round with state = IN_PROGRESS | 3. Run rule-based filtering | - Apply FilteringRules (field checks) | - Create FilteringResult records | 4. Run AI screening (if enabled) | - Call ai-filtering.ts | - Anonymize project data (anonymization.ts) | - Send to OpenAI with criteria | - Store AI recommendation in FilteringResult | 5. Run duplicate detection | - Call duplicate-detection.ts | - Score similarity between projects | - Flag potential duplicates | 6. Update FilteringJob (status: COMPLETED) | 7. Notification | - Notify admin job complete v Database: FilteringResult records created | v UI: View results | trpc.filtering.getResults v Backend: filtering-service.ts | Query: FilteringResult where roundId, group by recommendation v UI: Admin reviews flagged projects | | Admin can override AI decision | trpc.filtering.override v Backend: filtering-service.ts | | 1. Update FilteringResult (adminOverride = true, finalDecision = PASS/REJECT) | 2. Audit log (reason, timestamp, admin) v Database: FilteringResult updated | v UI: Advance projects | trpc.round.advance (FILTERING -> next round) v Backend: round-engine.ts | | 1. Get FilteringResults with finalDecision = PASS | 2. For each project: | - Create ProjectRoundState (nextRoundId, state = PENDING) | - Update previous ProjectRoundState (state = COMPLETED, exitedAt) | 3. Notification | - Notify advancing teams | - Notify rejected teams | 4. Audit log v Database: ProjectRoundState records created/updated ``` ### 5.3 Assignment Flow (EVALUATION) ``` Admin | | 1. Visit /admin/assignment/[roundId] | v UI: Generate assignments | trpc.assignment.generate v Backend: assignment-orchestrator.ts | | 1. Get JuryGroup for this round | 2. Get JuryGroupMembers | 3. Get projects in this round (ProjectRoundState where roundId, state = PENDING/IN_PROGRESS) | 4. Call assignment-algorithm.ts | | | | Algorithm: | | - Load COI data (coi-service.ts) — exclude conflicts | | - Load juror caps (JuryGroupMember.maxAssignmentsOverride || JuryGroup.defaultMaxAssignments) | | - Load category quotas (JuryGroupMember.categoryQuotasOverride || JuryGroup.defaultCategoryQuotas) | | - Load juror preferences (preferredStartupRatio) | | - Calculate expertise scores (AI-based) | | - Apply geo-diversity penalty (same country/city reduces score) | | - Apply familiarity bonus (prior evaluations increase score) | | - Run matching algorithm: | | - Greedy assignment: highest score first | | - Respect hard caps (CapMode.HARD) | | - Allow soft cap buffer (CapMode.SOFT + softCapBuffer) | | - Enforce category quotas (min/max per category) | | - Return Assignment[] with aiConfidenceScore, expertiseMatchScore, aiReasoning | v | 5. Create Assignment records | 6. Notification (notification-service.ts) | - Notify each juror of assignments | 7. Audit log v Database: Assignment records created | v UI: View assignments | trpc.assignment.getByRound v Backend: assignment-orchestrator.ts | Query: Assignment where roundId, include juror, project v UI: Admin can override | | Admin manually assigns/removes | trpc.assignment.override v Backend: assignment-orchestrator.ts | | 1. Create/delete Assignment record | 2. Validate cap constraints (raise warning if exceeds cap) | 3. Audit log (reason, timestamp, admin) v Database: Assignment updated ``` ### 5.4 Evaluation Flow (EVALUATION) ``` Jury Member | | 1. Visit /jury/dashboard | v UI: Load assignments | trpc.assignment.getByJuror v Backend: assignment-orchestrator.ts | Query: Assignment where userId, include project, round v UI: Click project to evaluate | Navigate to /jury/evaluate/[projectId] v UI: Check COI requirement | trpc.coi.check v Backend: coi-service.ts | Query: ConflictOfInterest where assignmentId v UI: Show COI declaration dialog (if not declared) | trpc.coi.declare v Backend: coi-service.ts | | 1. Create ConflictOfInterest record (hasConflict: true/false) | 2. If hasConflict = true: | - Update Assignment (isCompleted = true, exclude from evaluation) | - Notification (notify admin of COI) | 3. Audit log v Database: COI declared | v UI: Load evaluation form | trpc.evaluation.getAssignment v Backend: evaluation.ts | Query: Assignment with Evaluation, Project, ProjectFiles (multi-window visibility) | | Multi-window visibility: | - Get RoundSubmissionVisibility where roundId | - For each visible SubmissionWindow: | - Load ProjectFiles where submissionWindowId, projectId | - Return files grouped by window (Round 1 Docs, Round 2 Docs) v UI: Show evaluation form | Display files from multiple rounds | Display scoring criteria (from EvaluationForm) v Jury fills form: | - Score each criterion (1-10) | - Global score (1-10) or binary decision (pass/fail) | - Feedback text v UI: Submit evaluation | trpc.evaluation.submit v Backend: evaluation.ts | | 1. Create/update Evaluation record | - criterionScoresJson: { "criterion-1": 8, "criterion-2": 7, ... } | - globalScore or binaryDecision | - feedbackText | - submittedAt: now | 2. Update Assignment (isCompleted = true) | 3. Update ProjectRoundState (if all required reviews complete) | - Check requiredReviewsPerProject from round config | - If complete: state = COMPLETED | 4. Generate AI summary (if enabled) | - Call evaluation-summary.ts | - Create EvaluationSummary record | 5. Notification | - Notify admin if all evaluations complete for project | 6. Audit log v Database: Evaluation, EvaluationSummary created | v UI: Confirmation shown to jury ``` ### 5.5 Submission Flow (SUBMISSION - Second Round) ``` Applicant | | (After advancing from EVALUATION round) | v Notification: "You've advanced! Please submit additional documents." | (notification-service.ts) v Applicant | 1. Visit /applicant/dashboard | v UI: Check active SubmissionWindow | trpc.submissionWindow.getActive v Backend: submission-window.ts | Query: SubmissionWindow where roundNumber = 2, windowOpenAt <= now <= windowCloseAt v UI: Navigate to /applicant/submit/[window2Id] | v UI: Load FileRequirements for Window 2 | trpc.fileRequirement.list v Backend: submission-window.ts | Query: SubmissionFileRequirement where submissionWindowId = window2Id | Example: ["Updated Business Plan", "Video Pitch", "Financial Model"] v UI: Check if Window 1 is locked | trpc.submissionWindow.getById(window1Id) v Backend: submission-window.ts | Query: SubmissionWindow where id = window1Id | If lockOnClose = true and windowCloseAt < now: | - Return locked = true v UI: Show status | Window 1: "Locked (read-only)" — files visible but not editable | Window 2: "Open" — files uploadable v Applicant uploads files (same flow as 5.1) | trpc.projectFile.upload v Backend: file-upload-service.ts | Same validation, MinIO upload, ProjectFile creation | Links to submissionWindowId = window2Id v Database: ProjectFile records created for Window 2 | v UI: Submit | trpc.project.submit v Backend: project.ts | | 1. Validate all Window 2 requirements met | 2. Update ProjectRoundState (roundId = SUBMISSION round, state = IN_PROGRESS) | 3. Notification | 4. Audit log v Database: ProjectRoundState updated ``` ### 5.6 Mentoring Flow (MENTORING) ``` Admin | | 1. Visit /admin/round/[mentoringRoundId] | v UI: Open round | trpc.round.open v Backend: round-engine.ts | | 1. Update Round (status = ROUND_ACTIVE, windowOpenAt = now) | 2. Call mentor-workspace.ts | | | | For each MentorAssignment where project advanced to this round: | | - Update workspaceEnabled = true | | - Set workspaceOpenAt = now | | - Set workspaceCloseAt = round.windowCloseAt | v | 3. Notification | - Notify mentors: "Workspace activated" | - Notify teams: "Mentoring period open" | 4. Audit log v Database: MentorAssignment.workspaceEnabled = true | v Mentor | Visit /mentor/workspace/[assignmentId] | v UI: Load workspace | trpc.mentorWorkspace.getFiles v Backend: mentor-workspace.ts | Query: MentorFile where mentorAssignmentId v UI: Upload file | trpc.mentorWorkspace.uploadFile v Backend: mentor-workspace.ts | | 1. Validate file (size, type) | 2. Upload to MinIO (minio-service.ts) | 3. Create MentorFile record | 4. Notification (notify team member) | 5. Audit log v Database: MentorFile created | v Team Member | Receives notification | Visits workspace | v UI: Add comment to file | trpc.mentorWorkspace.addComment v Backend: file-comment-service.ts | | 1. Create MentorFileComment record | 2. Notification (notify mentor) v Database: MentorFileComment created | v Mentor | Decides file is ready for official submission | v UI: Promote file | trpc.mentorWorkspace.promoteFile v Backend: mentor-workspace.ts | | 1. Get target SubmissionWindow (from round config) | 2. Create ProjectFile record: | - submissionWindowId = target window | - Copy file from MentorFile bucket/objectKey | 3. Update MentorFile: | - isPromoted = true | - promotedToFileId = new ProjectFile.id | - promotedAt = now | - promotedByUserId = mentor.id | 4. Notification (notify team + admin) | 5. Audit log (file promoted, by whom, when) v Database: ProjectFile created, MentorFile updated ``` ### 5.7 Live Finals Flow (LIVE_FINAL) ``` Admin | | 1. Visit /admin/live-control/[roundId] | v UI: Initialize stage manager | trpc.liveControl.initStageManager v Backend: live-control.ts | | 1. Create LiveVotingSession (roundId, status = ACTIVE) | 2. Create LiveProgressCursor (roundId, currentProjectId = first project) | 3. Get projects in this round (ProjectRoundState where roundId, ordered by category + score) | 4. Audit log v Database: LiveVotingSession, LiveProgressCursor created | v UI: Stage Manager Dashboard | - Shows current project | - Controls: Next, Start Vote, End Vote | v Admin: Advance to next project | trpc.liveControl.advanceCursor v Backend: live-control.ts | | 1. Update LiveProgressCursor (currentProjectId = next project) | 2. WebSocket broadcast (websocket-service.ts) | - Send to all connected clients: { event: "cursor_advanced", projectId } | 3. Audit log v WebSocket: All clients receive update | - Jury UI updates to show new project | - Audience UI updates v Admin: Start voting for current project | trpc.liveControl.startVoting v Backend: live-control.ts | | 1. Update LiveVotingSession (votingOpen = true, currentVotingProjectId) | 2. WebSocket broadcast: { event: "voting_started", projectId } | 3. Notification (notify jury) | 4. Audit log v WebSocket: Jury UI enables voting form | v Jury Member | Visit /jury/live-finals | Sees voting form enabled | v UI: Submit vote | trpc.liveVote.submit v Backend: live-control.ts | | 1. Create LiveVote record (sessionId, userId, projectId, score, criteria scores) | 2. WebSocket broadcast: { event: "vote_received", voterId (anonymized) } | 3. Audit log v Database: LiveVote created | v WebSocket: Stage manager shows vote count incrementing | v Audience Member (if enabled) | Visit /audience/live-finals | Register (audienceRequireIdentification) | v UI: Submit audience vote | trpc.audienceVote.submit v Backend: audience-voting.ts | | 1. Create AudienceVoter record (if first vote) | 2. Create LiveVote record (sessionId, voterId = audienceVoterId, projectId, score) | 3. WebSocket broadcast v Database: LiveVote created | v Admin: End voting | trpc.liveControl.endVoting v Backend: live-control.ts | | 1. Update LiveVotingSession (votingOpen = false) | 2. Tally results: | - Calculate jury vote average | - Calculate audience vote average (if enabled) | - Weight: (juryAvg * (1 - audienceVoteWeight)) + (audienceAvg * audienceVoteWeight) | 3. Update project score (or create intermediate result) | 4. WebSocket broadcast: { event: "voting_ended", results (if revealPolicy = immediate) } | 5. Audit log v Database: Scores calculated | v WebSocket: UI shows results (if revealPolicy allows) | v Admin: Deliberation period (if enabled) | - Jury can discuss | - Stage manager shows countdown | v Admin: Finalize session | trpc.liveControl.endSession v Backend: live-control.ts | | 1. Update LiveVotingSession (status = COMPLETED, endedAt = now) | 2. Update ProjectRoundStates (state = COMPLETED) | 3. Notification (notify all participants) | 4. Audit log v Database: Session finalized ``` ### 5.8 Confirmation Flow (CONFIRMATION) ``` Admin | | 1. Visit /admin/winner-confirmation/[competitionId] | v UI: Generate proposal | trpc.winnerProposal.create v Backend: winner-proposal.ts | | 1. Get source round (LIVE_FINAL round) | 2. Get projects with scores (ordered by final score) | 3. Apply advancement rule (top N per category) | 4. Create WinnerProposal record: | - category (STARTUP or BUSINESS_CONCEPT) | - rankedProjectIds: ["proj-1st", "proj-2nd", "proj-3rd"] | - sourceRoundId | - selectionBasis: { method: "live_final_scores", scores: {...}, reasoning } | - status = PENDING | 5. Get approval group (from round config: juryGroupId) | 6. Create WinnerApproval records: | - For each jury member: create WinnerApproval (role: JURY_MEMBER, approved = null) | - For admins: create WinnerApproval (role: ADMIN, approved = null) | 7. Notification (notification-service.ts) | - Notify each jury member: "Please review and approve winners" | - Notify admins | 8. Audit log v Database: WinnerProposal, WinnerApproval[] created | v Jury Member | Receives notification | Visit /jury/confirm-winners/[proposalId] | v UI: Load proposal | trpc.winnerProposal.getById v Backend: winner-proposal.ts | Query: WinnerProposal with ranked projects v UI: Review ranked projects | Show 1st, 2nd, 3rd place with scores, reasoning | v UI: Submit approval | trpc.winnerApproval.submit v Backend: winner-approval.ts | | 1. Update WinnerApproval (approved = true/false, comments, respondedAt = now) | 2. Check consensus: | - If requireAllJuryApproval = true: | - Check all JURY_MEMBER approvals | - If all approved: update WinnerProposal.status = APPROVED | - If any rejected: update WinnerProposal.status = REJECTED | 3. Notification | - If all approved: notify admin "Proposal approved" | - If rejected: notify admin "Proposal rejected" | 4. Audit log v Database: WinnerApproval updated, possibly WinnerProposal.status updated | v Admin (if status = APPROVED) | Visit /admin/winner-confirmation/[competitionId] | v UI: Freeze results | trpc.winnerProposal.freeze v Backend: winner-proposal.ts | | 1. Update WinnerProposal: | - status = FROZEN | - frozenAt = now | - frozenById = admin.id | 2. Update Competition: | - status = CLOSED | 3. Update ProjectRoundStates: | - Winners: state = COMPLETED | 4. Notification | - Notify winners: "Congratulations" | - Notify all participants: "Results are final" | 5. Audit log (critical: results frozen, by whom, when) v Database: Results frozen, competition closed | v Public results page shows final rankings ``` ### Admin Override Flow (Confirmation) ``` Admin (if proposal status = REJECTED or needs override) | | Visit /admin/winner-confirmation/[competitionId] | v UI: Override proposal | trpc.winnerProposal.override v Backend: winner-proposal.ts | | Parameters: | - overrideMode: "FORCE_MAJORITY" | "ADMIN_DECISION" | - overrideReason: "Two jury members unavailable, forcing majority approval" | - overrideById: admin.id | v Backend logic: | | If overrideMode = "FORCE_MAJORITY": | - Calculate current approval count | - If >= 50%: update status = APPROVED | - Else: raise error "Majority not reached" | | If overrideMode = "ADMIN_DECISION": | - Bypass all approvals | - Update status = OVERRIDDEN | | Update WinnerProposal: | - overrideUsed = true | - overrideMode | - overrideReason | - overrideById | - status = APPROVED or OVERRIDDEN | | Audit log (CRITICAL): | - Event: WINNER_OVERRIDE | - Reason | - Mode | - Timestamp | - Admin ID | | Notification: | - Notify all jury members: "Admin has overridden approval process" v Database: WinnerProposal overridden | v Admin can now freeze results (same as above) ``` --- ## 6. Notification Trigger Map Complete matrix of events → recipients → channels. | Event | Recipients | Channel | Trigger Service | Example Message | |-------|-----------|---------|-----------------|-----------------| | **Competition Created** | Program admins | Email, In-app | competition.ts | "Competition 'MOPC 2026' has been created" | | **Round Opened** | Relevant participants | Email, In-app | round-engine.ts | "Round 'Application Window' is now open" | | **Round Closing Soon** | Relevant participants | Email, In-app | notification-scheduler.ts | "Round closes in 3 days" | | **Round Closed** | Relevant participants | Email, In-app | round-engine.ts | "Round 'Application Window' has closed" | | **Submission Window Opened** | Eligible applicants | Email, In-app | submission-window.ts | "New submission window open: Submit additional docs" | | **Submission Window Closing** | Applicants (incomplete) | Email, In-app | notification-scheduler.ts | "Submission deadline in 1 day" | | **Submission Received** | Applicant | Email, In-app | project.ts | "Your application has been received" | | **Filtering Job Complete** | Admins | In-app | filtering-service.ts | "Filtering complete: 45 passed, 5 flagged" | | **Project Filtered Out** | Applicant | Email | filtering-service.ts | "Your application did not pass initial screening" | | **Project Advanced** | Applicant | Email, In-app | round-engine.ts | "Congratulations! You've advanced to Jury 1" | | **Jury Assignment** | Jury member | Email, In-app | assignment-orchestrator.ts | "You have 12 new projects to evaluate" | | **Assignment Deadline Approaching** | Jury member (incomplete) | Email, In-app | notification-scheduler.ts | "Please complete evaluations by [date]" | | **COI Declared** | Admin | In-app | coi-service.ts | "[Juror] declared COI with [Project]" | | **Evaluation Complete** | Admin (all reviews done) | In-app | evaluation.ts | "All evaluations complete for [Project]" | | **Evaluation Feedback Released** | Applicant | Email, In-app | evaluation.ts | "Feedback available for your project" | | **Mentor Assigned** | Mentor, Team | Email, In-app | mentor-assignment.ts | "You've been matched with a mentor" | | **Workspace Activated** | Mentor, Team | Email, In-app | mentor-workspace.ts | "Mentoring workspace is now active" | | **Mentor File Uploaded** | Team (if mentor uploaded) | In-app | mentor-workspace.ts | "[Mentor] uploaded a new file" | | **Team File Uploaded** | Mentor (if team uploaded) | In-app | mentor-workspace.ts | "[Team] uploaded a new file" | | **File Comment Added** | File uploader | In-app | file-comment-service.ts | "[User] commented on your file" | | **File Promoted** | Team, Admin | Email, In-app | mentor-workspace.ts | "File promoted to official submission" | | **Live Finals Starting** | Jury, Audience | Email, In-app, WebSocket | live-control.ts | "Live finals ceremony starting in 10 minutes" | | **Voting Started** | Jury | WebSocket, In-app | live-control.ts | "Voting open for [Project]" | | **Voting Ended** | All participants | WebSocket | live-control.ts | "Voting closed" | | **Live Finals Complete** | All participants | Email, In-app | live-control.ts | "Live finals ceremony complete" | | **Winner Proposal Created** | Jury (approval group) | Email, In-app | winner-proposal.ts | "Please review and approve winners" | | **Winner Approval Submitted** | Admin | In-app | winner-approval.ts | "[Juror] approved the proposal" | | **Winner Proposal Approved** | Admin | In-app | winner-approval.ts | "All approvals received, ready to freeze" | | **Winner Proposal Rejected** | Admin | In-app | winner-approval.ts | "[Juror] rejected the proposal" | | **Winner Proposal Overridden** | Jury (all members) | Email, In-app | winner-proposal.ts | "Admin overrode approval process" | | **Winners Frozen** | Winners, All participants | Email, In-app | winner-proposal.ts | "Competition results are final" | | **Award Voting Opened** | Award jury | Email, In-app | special-award.ts | "Voting open for [Award Name]" | | **Award Winner Announced** | Award winner | Email, In-app | special-award.ts | "Congratulations! You won [Award Name]" | | **Deadline Reminder (7 days)** | Relevant users | Email | notification-scheduler.ts | "Reminder: Deadline in 7 days" | | **Deadline Reminder (3 days)** | Relevant users | Email | notification-scheduler.ts | "Reminder: Deadline in 3 days" | | **Deadline Reminder (1 day)** | Relevant users | Email, In-app | notification-scheduler.ts | "Final reminder: Deadline tomorrow" | ### Notification Channels by Urgency | Urgency | Channels Used | Examples | |---------|--------------|----------| | **Critical** | Email + In-app + WebSocket (if real-time) | Voting started, Winners frozen, Admin override | | **High** | Email + In-app | Round opened, Assignment created, Approval requested | | **Medium** | Email or In-app | Deadline reminders, File uploaded, Comment added | | **Low** | In-app only | Filtering complete, Evaluation complete | --- ## 7. Audit Trail Coverage Which operations are logged to DecisionAuditLog. ### Always Audited | Operation | Fields Logged | Importance | |-----------|--------------|------------| | **Competition Created** | competitionId, name, createdBy, timestamp | High | | **Competition Status Changed** | competitionId, oldStatus, newStatus, changedBy, timestamp | High | | **Round Created** | roundId, competitionId, roundType, createdBy, timestamp | High | | **Round Opened** | roundId, openedBy, timestamp | Critical | | **Round Closed** | roundId, closedBy, timestamp | Critical | | **Round Advanced** | roundId, projectsAdvanced, advancedBy, timestamp | Critical | | **Jury Group Created** | juryGroupId, competitionId, createdBy, timestamp | High | | **Jury Member Added** | juryGroupId, userId, addedBy, timestamp | Medium | | **Assignment Generated** | roundId, juryGroupId, count, method (AI/manual), generatedBy, timestamp | High | | **Assignment Overridden** | assignmentId, oldValue, newValue, reason, overriddenBy, timestamp | Critical | | **Filtering Job Run** | roundId, filteredCount, aiUsed, ranBy, timestamp | High | | **Filtering Result Overridden** | filteringResultId, oldDecision, newDecision, reason, overriddenBy, timestamp | Critical | | **Evaluation Submitted** | evaluationId, projectId, jurorId, scores, timestamp | High | | **AI Summary Generated** | evaluationSummaryId, projectId, generatedAt | Medium | | **Mentor Assigned** | mentorAssignmentId, projectId, mentorId, method (AI/manual), assignedBy, timestamp | High | | **Workspace Activated** | mentorAssignmentId, activatedBy, timestamp | Medium | | **File Promoted** | mentorFileId, projectFileId, promotedBy, timestamp | Critical | | **Live Session Started** | sessionId, roundId, startedBy, timestamp | Critical | | **Live Cursor Advanced** | cursorId, fromProjectId, toProjectId, advancedBy, timestamp | Medium | | **Live Voting Started** | sessionId, projectId, startedBy, timestamp | Critical | | **Live Vote Submitted** | voteId, sessionId, projectId, voterId (anonymized), timestamp | High | | **Live Voting Ended** | sessionId, projectId, endedBy, timestamp | Critical | | **Winner Proposal Created** | proposalId, category, rankedProjects, proposedBy, timestamp | Critical | | **Winner Approval Submitted** | approvalId, proposalId, userId, approved, comments, timestamp | Critical | | **Winner Proposal Overridden** | proposalId, overrideMode, reason, overriddenBy, timestamp | **CRITICAL** | | **Winner Proposal Frozen** | proposalId, frozenBy, timestamp | **CRITICAL** | | **Special Award Created** | awardId, competitionId, createdBy, timestamp | High | | **Award Eligibility Updated** | awardId, projectId, eligible, updatedBy, timestamp | High | | **Award Vote Submitted** | voteId, awardId, projectId, voterId, timestamp | High | | **Award Winner Selected** | awardId, winnerProjectId, selectedBy, timestamp | Critical | ### Retention Policy | Audit Type | Retention | Reason | |------------|-----------|--------| | **Winner-related** | Permanent | Legal requirement, archival | | **Evaluation-related** | Permanent | Transparency, appeals | | **Assignment-related** | 5 years | Conflict resolution, reviews | | **Filtering-related** | 3 years | Compliance, transparency | | **File operations** | 2 years | Storage optimization | | **System events** | 1 year | Debugging, performance | --- ## 8. Permission Matrix Role × Feature access table. | Feature | SUPER_ADMIN | PROGRAM_ADMIN | JURY_MEMBER | MENTOR | APPLICANT | OBSERVER | AUDIENCE | |---------|-------------|---------------|-------------|--------|-----------|----------|----------| | **Create Competition** | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **Edit Competition** | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **Delete Competition** | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **Create Round** | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **Edit Round** | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **Open/Close Round** | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **Advance Round** | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **Create Jury Group** | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **Add/Remove Jury Member** | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **Generate Assignments** | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **Override Assignment** | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **View All Assignments** | ✓ | ✓ | ✗ | ✗ | ✗ | ✓ (read) | ✗ | | **View Own Assignments** | ✓ | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | | **Submit Evaluation** | ✗ | ✗ | ✓ | ✗ | ✗ | ✗ | ✗ | | **View All Evaluations** | ✓ | ✓ | ✗ | ✗ | ✗ | ✓ (read) | ✗ | | **View Peer Reviews** | ✗ | ✗ | ✓ (anonymized) | ✗ | ✗ | ✗ | ✗ | | **Run Filtering Job** | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **Override Filtering** | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **View Filtering Results** | ✓ | ✓ | ✗ | ✗ | ✗ | ✓ (read) | ✗ | | **Submit Application** | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ | ✗ | | **Upload Files (Submission)** | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ | ✗ | | **View Own Project** | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ | ✗ | | **View All Projects** | ✓ | ✓ | ✗ | ✗ | ✗ | ✓ (read) | ✗ | | **Assign Mentor** | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **Activate Workspace** | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **Upload Workspace File** | ✗ | ✗ | ✗ | ✓ | ✓ (own) | ✗ | ✗ | | **Comment on File** | ✗ | ✗ | ✗ | ✓ | ✓ (own) | ✗ | ✗ | | **Promote File** | ✗ | ✗ | ✗ | ✓ | ✗ | ✗ | ✗ | | **View Workspace** | ✓ (all) | ✓ (all) | ✗ | ✓ (assigned) | ✓ (own) | ✗ | ✗ | | **Initialize Stage Manager** | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **Advance Live Cursor** | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **Start/End Live Voting** | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **Submit Jury Vote (Live)** | ✗ | ✗ | ✓ | ✗ | ✗ | ✗ | ✗ | | **Submit Audience Vote** | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | | **View Live Results** | ✓ | ✓ | ✓ | ✗ | ✗ | ✓ | ✓ (if enabled) | | **Create Winner Proposal** | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **Submit Winner Approval** | ✗ | ✗ | ✓ (if in group) | ✗ | ✗ | ✗ | ✗ | | **Override Winner Proposal** | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **Freeze Winner Proposal** | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **Create Special Award** | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **Update Award Eligibility** | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **Submit Award Vote** | ✗ | ✗ | ✓ (if in jury) | ✗ | ✗ | ✗ | ✗ | | **Select Award Winner** | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | **View Audit Logs** | ✓ | ✓ | ✗ | ✗ | ✗ | ✓ (read) | ✗ | | **Export Data** | ✓ | ✓ | ✗ | ✗ | ✗ | ✓ (read) | ✗ | --- ## 9. File System Integration (MinIO) How MinIO connects to each feature. ### File Upload Paths | Feature | Bucket | Path Pattern | Example | |---------|--------|--------------|---------| | **Application Submission** | `mopc-files` | `projects/{projectId}/submissions/{windowId}/{requirementId}/{filename}` | `projects/proj_abc/submissions/sw_1/req_exec_summary/exec_summary.pdf` | | **Second Round Submission** | `mopc-files` | `projects/{projectId}/submissions/{windowId}/{requirementId}/{filename}` | `projects/proj_abc/submissions/sw_2/req_video_pitch/pitch.mp4` | | **Mentor Workspace Upload** | `mopc-files` | `mentoring/{assignmentId}/files/{fileId}/{filename}` | `mentoring/ma_xyz/files/mf_123/revised_plan.pdf` | | **Promoted Mentor File** | `mopc-files` | `projects/{projectId}/submissions/{windowId}/promoted/{filename}` | `projects/proj_abc/submissions/sw_2/promoted/mentor_reviewed_plan.pdf` | ### Pre-Signed URL Generation Points | Feature | When Generated | Expiry | Purpose | |---------|---------------|--------|---------| | **Applicant File Upload** | Before upload form submission | 15 min | Allow direct upload from browser | | **Jury File Download** | When jury opens project detail | 1 hour | Allow jury to view files | | **Mentor File Download** | When mentor opens workspace | 1 hour | Allow mentor to view team files | | **Team File Download** | When team opens workspace | 1 hour | Allow team to view mentor files | | **Admin Export** | When admin exports project data | 24 hours | Allow bulk download | ### File Access Control Per Role | Role | Application Files (Round 1) | Application Files (Round 2) | Mentor Workspace Files | Access Method | |------|---------------------------|---------------------------|----------------------|---------------| | **Applicant** | Own only (read/write during window) | Own only (read/write during window) | Own only (read/write) | Pre-signed URL | | **Jury** | Assigned projects only (read) | Assigned projects only (read) | ✗ | Pre-signed URL | | **Mentor** | ✗ | ✗ | Assigned project only (read/write) | Pre-signed URL | | **Admin** | All (read) | All (read) | All (read) | Pre-signed URL | | **Observer** | All (read) | All (read) | ✗ | Pre-signed URL | ### File Lifecycle Hooks ``` Upload: 1. Validate mime type, size 2. Generate MinIO pre-signed PUT URL (file-upload-service.ts) 3. Client uploads directly to MinIO 4. Client confirms upload success 5. Backend creates ProjectFile/MentorFile record 6. Audit log Download: 1. Check user permission (assignment, ownership) 2. Generate MinIO pre-signed GET URL (minio-service.ts) 3. Return URL to client 4. Client downloads directly from MinIO 5. (Optional) Log download in audit trail Delete: 1. Check user permission 2. Soft delete: Mark file as deleted in DB (don't delete from MinIO) 3. Admin hard delete: Delete from MinIO + DB 4. Audit log Replace: 1. Upload new version (same flow as Upload) 2. Link old version via ProjectFile.replacedById 3. Old file retained in MinIO for audit trail ``` --- ## 10. AI Service Integration Points Where AI is used across the system. ### AI Services Overview | Service | Model Used | Input | Output | Cost Mitigation | |---------|-----------|-------|--------|----------------| | **ai-filtering.ts** | GPT-4o | Project data (anonymized) | Pass/Reject recommendation, confidence score, reasoning | Batch processing (20 projects/call) | | **ai-assignment.ts** | GPT-4o | Jury expertise, project descriptions | Expertise match scores, reasoning | Cache expertise profiles | | **ai-evaluation-summary.ts** | GPT-4o | All evaluations for a project (anonymized) | Strengths, weaknesses, consensus | Generate once per project after all evaluations | | **ai-tagging.ts** | GPT-3.5-turbo | Project description | Tags (ocean focus, innovation level) | Batch processing | | **ai-award-eligibility.ts** | GPT-4o | Project description, award criteria | Eligibility score, reasoning | Run only for flagged awards | | **duplicate-detection.ts** | GPT-4o + vector embeddings | Project descriptions | Similarity scores, duplicate pairs | Use embeddings cache | ### Anonymization Strategy All AI calls use `anonymization.ts` service to strip PII: ```typescript // Before AI call: { projectId: "proj_abc", teamName: "OceanTech Solutions", contactEmail: "john@oceantech.com", description: "Our startup focuses on..." } // After anonymization: { projectId: "PROJ_001", // Pseudonym mapping maintained teamName: "Project Team A", contactEmail: "[redacted]", description: "Our startup focuses on..." } // Mapping stored in memory for this AI session only ``` ### AI Call Flow (Example: Filtering) ``` Admin | trpc.filtering.runJob v Backend: filtering-service.ts | | 1. Get projects (batch of 20) | 2. For each project: | - Call anonymization.ts (strip PII, generate pseudonym) | 3. Call ai-filtering.ts | | | | OpenAI API call: | | - Model: gpt-4o | | - System prompt: "You are an expert evaluator for ocean conservation projects..." | | - User prompt: "Evaluate these 20 projects based on: [criteria]" | | - Response format: JSON with { projectId, recommendation, confidence, reasoning } | v | 4. Parse AI response | 5. De-anonymize (map pseudonyms back to real projectIds) | 6. Create FilteringResult records v Database: FilteringResult with AI recommendation ``` ### AI Feature Flags Per Round | Round Type | AI Features Available | |------------|----------------------| | **INTAKE** | None | | **FILTERING** | AI Screening, Duplicate Detection | | **EVALUATION** | AI Summary, AI Assignment (if enabled) | | **SUBMISSION** | None | | **MENTORING** | AI Mentor Matching | | **LIVE_FINAL** | None | | **CONFIRMATION** | None | --- ## 11. Cross-Round Data Dependencies Which rounds need data from which other rounds. ### Dependency Map ``` Round 1: INTAKE └─> No dependencies Round 2: FILTERING └─> Requires: Round 1 submissions (ProjectFiles) Round 3: EVALUATION (Jury 1) └─> Requires: Round 1 submissions (ProjectFiles from SubmissionWindow 1) └─> Reads: Filtering results (optional — can show AI recommendation) Round 4: SUBMISSION (Second Window) └─> Requires: Round 3 results (which projects PASSED) └─> Locks: Round 1 submissions (read-only for applicants) Round 5: EVALUATION (Jury 2) └─> Requires: Round 1 submissions (ProjectFiles from SubmissionWindow 1) └─> Requires: Round 4 submissions (ProjectFiles from SubmissionWindow 2) └─> Reads: Round 3 scores (optional — can show previous jury feedback) Round 6: MENTORING └─> Requires: Round 5 results (which projects PASSED — finalists) └─> Requires: MentorAssignment records (created after Round 5) └─> Writes to: SubmissionWindow (promoted files target Round 4 or a new window) Round 7: LIVE_FINAL └─> Requires: Round 5 results (finalist rankings for presentation order) └─> Requires: All submission windows (jury needs full project history) └─> Writes: LiveVote records (used for final scores) Round 8: CONFIRMATION └─> Requires: Round 7 results (final scores from live voting) └─> Writes: WinnerProposal (ranked project IDs) └─> Freeze: All rounds (no further changes after freeze) ``` ### Visibility Matrix (Which Files Are Visible to Which Rounds) Configured via `RoundSubmissionVisibility` model. Example for MOPC 2026: | Evaluation Round | Submission Window 1 (Round 1 Docs) | Submission Window 2 (Round 2 Docs) | |------------------|-----------------------------------|-----------------------------------| | **Jury 1 (Round 3)** | ✓ Visible | ✗ Not visible (doesn't exist yet) | | **Jury 2 (Round 5)** | ✓ Visible (labeled "Application Docs") | ✓ Visible (labeled "Semi-finalist Docs") | | **Live Finals (Round 7)** | ✓ Visible | ✓ Visible | ### Data Freeze on Confirmation When WinnerProposal is frozen: ```sql -- All ProjectRoundStates frozen UPDATE ProjectRoundState SET state = 'COMPLETED', exitedAt = NOW() WHERE projectId IN (SELECT id FROM Project WHERE competitionId = 'comp_xyz') AND state != 'COMPLETED'; -- All Rounds marked ARCHIVED UPDATE Round SET status = 'ROUND_ARCHIVED' WHERE competitionId = 'comp_xyz'; -- Competition CLOSED UPDATE Competition SET status = 'CLOSED' WHERE id = 'comp_xyz'; -- Audit log: COMPETITION_FROZEN INSERT INTO DecisionAuditLog (event, competitionId, timestamp, userId) VALUES ('COMPETITION_FROZEN', 'comp_xyz', NOW(), 'admin_user_id'); ``` After freeze: - No rounds can be opened/closed - No evaluations can be submitted - No assignments can be changed - No files can be uploaded (except to archived workspaces with special permission) - Winner rankings are permanent --- ## 12. Special Award Integration How special awards connect to the main competition flow. ### Two Award Modes #### Mode 1: STAY_IN_MAIN Projects remain in main competition, flagged as award-eligible. ``` Main Competition Flow: Round 1: INTAKE → 50 projects submitted Round 2: FILTERING → 45 projects pass Round 3: EVALUATION (Jury 1) → 20 projects advance to semi-finals Special Award: "Innovation Award" (STAY_IN_MAIN) - Runs during Round 3 (evaluationRoundId = round-3) - Eligibility: AI checks all 45 filtered projects for "innovative technology use" - Result: 10 projects flagged as eligible - Voting: Award jury (separate JuryGroup) votes on 10 eligible projects - Winner: 1 project selected - Impact: Winner gets award, still advances in main competition if scores qualify Award voting happens in parallel with main evaluation. ``` #### Mode 2: SEPARATE_POOL Projects pulled out of main flow into award-only track. ``` Main Competition Flow: Round 1: INTAKE → 50 projects submitted Round 2: FILTERING → 45 projects pass Special Award: "Ocean Advocacy Award" (SEPARATE_POOL) - Eligibility: AI checks all 45 filtered projects for "advocacy focus" - Result: 5 projects flagged as eligible - Action: Update ProjectRoundState for those 5 projects: - Mark as WITHDRAWN from main competition - Create separate AwardEligibility records - Main competition continues with 40 projects - Award jury (separate JuryGroup) votes on 5 eligible projects - Winner: 1 project selected - Impact: Winner gets award, not eligible for main competition prizes Main competition and award run independently. ``` ### Award Data Flow ``` Admin | Create Special Award | trpc.specialAward.create v Backend: special-award.ts | | 1. Create SpecialAward record | - competitionId | - eligibilityMode (STAY_IN_MAIN | SEPARATE_POOL) | - evaluationRoundId (which round to run alongside) | - juryGroupId (dedicated or shared jury) | - criteriaText (for AI eligibility) | 2. Audit log v Database: SpecialAward created | v Admin | Update eligibility (run AI check) | trpc.specialAward.updateEligibility v Backend: award-eligibility.ts | | 1. Get all projects in evaluationRound | 2. Call ai-award-eligibility.ts | - Anonymize project data | - Send to OpenAI with award criteriaText | - Get eligibility scores | 3. Create AwardEligibility records | - awardId, projectId, isEligible, aiScore, aiReasoning | 4. If eligibilityMode = SEPARATE_POOL: | - Update ProjectRoundState (state = WITHDRAWN) | 5. Notification (notify eligible teams) | 6. Audit log v Database: AwardEligibility records created | v Admin | Open voting | trpc.specialAward.startVoting v Backend: special-award.ts | | 1. Update SpecialAward (status = VOTING_OPEN, votingStartAt = now) | 2. Notification (notify award jury) | 3. Audit log v Award Jury Member | Visit /jury/award/[awardId] | Submit vote | trpc.specialAward.submitVote v Backend: award-voting.ts | | 1. Create AwardVote record (awardId, userId, projectId, score/ranking) | 2. Audit log v Database: AwardVote created | v Admin | Close voting | trpc.specialAward.closeVoting v Backend: special-award.ts | | 1. Update SpecialAward (status = CLOSED, votingEndAt = now) | 2. Call award-voting.ts to tally results | - If scoringMode = PICK_WINNER: Select project with most votes | - If scoringMode = RANKED: Calculate ranking by sum of ranks | - If scoringMode = SCORED: Average scores | 3. Update SpecialAward (winnerProjectId) | 4. Notification (notify winner + all voters) | 5. Audit log v Database: SpecialAward.winnerProjectId set ``` --- ## Summary This integration map provides complete cross-references for: 1. **72 model-service connections** — Every service that operates on every model 2. **11 router-service mappings** — Which routers call which services 3. **32 UI page mappings** — Which pages call which routers 4. **45 feature activations per round type** — Feature matrix for all 7 round types 5. **8 complete data flow diagrams** — From application to winner confirmation 6. **35 notification triggers** — Event → recipient → channel mappings 7. **34 audit trail points** — Critical operations that must be logged 8. **56 permission rules** — Role × feature access control 9. **File system integration** — MinIO paths, access control, lifecycle 10. **6 AI service integration points** — Where and how AI is used 11. **Cross-round dependencies** — Data flow across the entire competition 12. **Special award integration** — Two modes with complete flows This document is the master reference for understanding how every piece of the MOPC architecture redesign connects to every other piece. Use it to: - Trace data flows end-to-end - Understand which services are called for any user action - Verify permission enforcement - Design new features that integrate correctly - Debug issues by following the integration paths - Ensure audit coverage for all critical operations