# Current System Audit: MOPC Platform

**Document Version:** 1.0
**Date:** 2026-02-15
**Status:** Complete
**Purpose:** Comprehensive inventory of all data models, services, routers, pages, and capabilities in the MOPC platform as of February 2026.

---

## Table of Contents

1. [Data Models](#1-data-models)
2. [Enums](#2-enums)
3. [Services](#3-services)
4. [tRPC Routers](#4-trpc-routers)
5. [UI Pages](#5-ui-pages)
6. [Strengths](#6-strengths-of-current-system)
7. [Weaknesses](#7-weaknesses-of-current-system)

---

## 1. Data Models

### 1.1 Competition Structure Models

| Model | Purpose | Key Fields | Relations |
|-------|---------|------------|-----------|
| **Pipeline** | Top-level competition round container | `programId`, `name`, `slug`, `status`, `settingsJson` | → Program, → Track[] |
| **Track** | Competition lane (MAIN or AWARD) | `pipelineId`, `name`, `kind`, `routingMode`, `decisionMode`, `sortOrder`, `settingsJson` | → Pipeline, → Stage[], → ProjectStageState[], ← SpecialAward? |
| **Stage** | Individual competition phase within a track | `trackId`, `stageType`, `name`, `slug`, `status`, `sortOrder`, `configJson`, `windowOpenAt`, `windowCloseAt` | → Track, → ProjectStageState[], → StageTransition[], → Cohort[], → LiveProgressCursor?, → LiveVotingSession? |
| **StageTransition** | Defines valid stage-to-stage movements | `fromStageId`, `toStageId`, `isDefault`, `guardJson` | → Stage (from), → Stage (to) |
| **ProjectStageState** | Tracks project position in pipeline | `projectId`, `trackId`, `stageId`, `state`, `enteredAt`, `exitedAt`, `metadataJson` | → Project, → Track, → Stage |
| **Cohort** | Groups projects for live voting | `stageId`, `name`, `votingMode`, `isOpen`, `windowOpenAt`, `windowCloseAt` | → Stage, → CohortProject[] |
| **CohortProject** | Project membership in a cohort | `cohortId`, `projectId`, `sortOrder` | → Cohort, → Project |

### 1.2 Project & Submission Models

| Model | Purpose | Key Fields | Relations |
|-------|---------|------------|-----------|
| **Project** | Core project/application entity | `programId`, `title`, `teamName`, `description`, `competitionCategory`, `oceanIssue`, `country`, `geographicZone`, `institution`, `wantsMentorship`, `foundedAt`, `status`, `submissionSource`, `submittedByEmail`, `submittedAt`, `tags`, `metadataJson`, `isDraft` | → Program, → ProjectFile[], → Assignment[], → TeamMember[], → MentorAssignment?, → FilteringResult[], → AwardEligibility[], → ProjectStageState[], → CohortProject[] |
| **ProjectFile** | File uploads attached to projects | `projectId`, `requirementId`, `fileType`, `fileName`, `mimeType`, `size`, `bucket`, `objectKey`, `version`, `replacedById`, `isLate` | → Project, → FileRequirement?, → ProjectFile (versioning) |
| **FileRequirement** | Defines required file uploads per stage | `stageId`, `name`, `description`, `acceptedMimeTypes`, `maxSizeMB`, `isRequired`, `sortOrder` | → Stage, ← ProjectFile[] |
| **TeamMember** | Team composition for projects | `projectId`, `userId`, `role`, `title` | → Project, → User |

### 1.3 Jury & Evaluation Models

| Model | Purpose | Key Fields | Relations |
|-------|---------|------------|-----------|
| **Assignment** | Jury member assigned to evaluate a project | `userId`, `projectId`, `stageId`, `method`, `isRequired`, `isCompleted`, `aiConfidenceScore`, `expertiseMatchScore`, `aiReasoning` | → User, → Project, → Stage, → Evaluation?, → ConflictOfInterest? |
| **Evaluation** | Jury member's assessment of a project | `assignmentId`, `formId`, `status`, `criterionScoresJson`, `globalScore`, `binaryDecision`, `feedbackText`, `version`, `submittedAt` | → Assignment, → EvaluationForm |
| **EvaluationForm** | Configurable evaluation criteria per stage | `stageId`, `version`, `criteriaJson`, `scalesJson`, `isActive` | → Stage, ← Evaluation[] |
| **ConflictOfInterest** | COI declarations by jury members | `assignmentId`, `userId`, `projectId`, `hasConflict`, `conflictType`, `description`, `declaredAt`, `reviewedById`, `reviewAction` | → Assignment, → User, → User (reviewer) |
| **GracePeriod** | Extended deadlines for specific jury members | `stageId`, `userId`, `projectId`, `extendedUntil`, `reason`, `grantedById` | → Stage, → User, → User (granter) |
| **EvaluationSummary** | AI-generated synthesis of evaluations | `projectId`, `stageId`, `summaryJson`, `generatedAt`, `generatedById`, `model`, `tokensUsed` | → Project, → Stage, → User |
| **EvaluationDiscussion** | Discussion thread for deliberation | `projectId`, `stageId`, `status`, `createdAt`, `closedAt`, `closedById` | → Project, → Stage, → User, → DiscussionComment[] |
| **DiscussionComment** | Individual comment in discussion | `discussionId`, `userId`, `content`, `createdAt` | → EvaluationDiscussion, → User |

### 1.4 Live Voting Models

| Model | Purpose | Key Fields | Relations |
|-------|---------|------------|-----------|
| **LiveVotingSession** | Live final event configuration | `stageId`, `status`, `currentProjectIndex`, `currentProjectId`, `votingStartedAt`, `votingEndsAt`, `projectOrderJson`, `votingMode`, `criteriaJson`, `allowAudienceVotes`, `audienceVoteWeight`, `tieBreakerMethod` | → Stage, → LiveVote[], → AudienceVoter[] |
| **LiveVote** | Individual vote during live event | `sessionId`, `projectId`, `userId`, `score`, `isAudienceVote`, `votedAt`, `criterionScoresJson`, `audienceVoterId` | → LiveVotingSession, → User?, → AudienceVoter? |
| **AudienceVoter** | Anonymous audience participant | `sessionId`, `token`, `identifier`, `identifierType`, `ipAddress`, `userAgent` | → LiveVotingSession, → LiveVote[] |
| **LiveProgressCursor** | Real-time cursor for live presentation | `stageId`, `sessionId`, `activeProjectId`, `activeOrderIndex`, `isPaused` | → Stage |

### 1.5 Awards Models

| Model | Purpose | Key Fields | Relations |
|-------|---------|------------|-----------|
| **SpecialAward** | Special prize/recognition category | `programId`, `trackId`, `name`, `description`, `status`, `criteriaText`, `autoTagRulesJson`, `useAiEligibility`, `scoringMode`, `maxRankedPicks`, `votingStartAt`, `votingEndAt`, `winnerProjectId`, `winnerOverridden`, `eligibilityJobStatus` | → Program, → Track?, → Project (winner), → AwardEligibility[], → AwardJuror[], → AwardVote[] |
| **AwardEligibility** | AI-determined award eligibility | `awardId`, `projectId`, `method`, `eligible`, `aiReasoningJson`, `overriddenBy`, `overriddenAt` | → SpecialAward, → Project, → User? |
| **AwardJuror** | Jury panel for special award | `awardId`, `userId` | → SpecialAward, → User |
| **AwardVote** | Vote for special award winner | `awardId`, `userId`, `projectId`, `rank`, `votedAt` | → SpecialAward, → User, → Project |

### 1.6 Mentoring Models

| Model | Purpose | Key Fields | Relations |
|-------|---------|------------|-----------|
| **MentorAssignment** | Mentor-project pairing | `projectId`, `mentorId`, `method`, `assignedAt`, `assignedBy`, `aiConfidenceScore`, `expertiseMatchScore`, `completionStatus` | → Project (unique), → User (mentor), → MentorNote[], → MentorMilestoneCompletion[] |
| **MentorMessage** | Chat messages between mentor and team | `projectId`, `senderId`, `message`, `isRead` | → Project, → User |
| **MentorNote** | Private notes by mentor/admin | `mentorAssignmentId`, `authorId`, `content`, `isVisibleToAdmin` | → MentorAssignment, → User |
| **MentorMilestone** | Program-wide mentorship checkpoints | `programId`, `name`, `description`, `isRequired`, `deadlineOffsetDays`, `sortOrder` | → Program, → MentorMilestoneCompletion[] |
| **MentorMilestoneCompletion** | Completion record for milestones | `milestoneId`, `mentorAssignmentId`, `completedById`, `completedAt` | → MentorMilestone, → MentorAssignment, → User |

### 1.7 Filtering Models

| Model | Purpose | Key Fields | Relations |
|-------|---------|------------|-----------|
| **FilteringRule** | Automated screening rule | `stageId`, `name`, `ruleType`, `configJson`, `priority`, `isActive` | → Stage |
| **FilteringResult** | Per-project filtering outcome | `stageId`, `projectId`, `outcome`, `ruleResultsJson`, `aiScreeningJson`, `overriddenBy`, `overriddenAt`, `overrideReason`, `finalOutcome` | → Stage, → Project, → User? |
| **FilteringJob** | Progress tracking for filtering runs | `stageId`, `status`, `totalProjects`, `processedCount`, `passedCount`, `filteredCount`, `flaggedCount`, `errorMessage`, `startedAt`, `completedAt` | → Stage |
| **AssignmentJob** | Progress tracking for assignment generation | `stageId`, `status`, `totalProjects`, `processedCount`, `suggestionsCount`, `suggestionsJson`, `errorMessage`, `fallbackUsed` | → Stage |
| **TaggingJob** | Progress tracking for AI tagging | `programId`, `status`, `totalProjects`, `processedCount`, `taggedCount`, `skippedCount`, `failedCount`, `errorsJson` | → Program? |

### 1.8 Users & Auth Models

| Model | Purpose | Key Fields | Relations |
|-------|---------|------------|-----------|
| **User** | Platform user account | `email`, `name`, `role`, `status`, `expertiseTags`, `maxAssignments`, `country`, `bio`, `phoneNumber`, `notificationPreference`, `digestFrequency`, `preferredWorkload`, `passwordHash`, `inviteToken`, `onboardingCompletedAt` | → Assignment[], → GracePeriod[], → LiveVote[], → TeamMember[], → MentorAssignment[], → AwardJuror[], → ConflictOfInterest[], → InAppNotification[] |
| **Account** | NextAuth provider accounts | `userId`, `provider`, `providerAccountId`, `access_token`, `refresh_token` | → User |
| **Session** | NextAuth active sessions | `userId`, `sessionToken`, `expires` | → User |
| **VerificationToken** | NextAuth magic link tokens | `identifier`, `token`, `expires` | (standalone) |

### 1.9 Audit & Logging Models

| Model | Purpose | Key Fields | Relations |
|-------|---------|------------|-----------|
| **AuditLog** | General platform activity log | `userId`, `action`, `entityType`, `entityId`, `detailsJson`, `previousDataJson`, `ipAddress`, `userAgent`, `sessionId`, `timestamp` | → User? |
| **DecisionAuditLog** | Pipeline decision tracking | `eventType`, `entityType`, `entityId`, `actorId`, `detailsJson`, `snapshotJson`, `createdAt` | (no FK relations) |
| **OverrideAction** | Manual admin overrides log | `entityType`, `entityId`, `previousValue`, `newValueJson`, `reasonCode`, `reasonText`, `actorId`, `createdAt` | (no FK relations) |
| **AIUsageLog** | AI API consumption tracking | `userId`, `action`, `entityType`, `entityId`, `model`, `promptTokens`, `completionTokens`, `estimatedCostUsd`, `status`, `errorMessage` | (no FK relations) |
| **NotificationLog** | Email/SMS delivery tracking | `userId`, `channel`, `provider`, `type`, `status`, `externalId`, `errorMsg` | → User |

### 1.10 Program & Resources Models

| Model | Purpose | Key Fields | Relations |
|-------|---------|------------|-----------|
| **Program** | Competition edition/year | `name`, `slug`, `year`, `status`, `description`, `settingsJson` | → Pipeline[], → Project[], → LearningResource[], → Partner[], → SpecialAward[] |
| **LearningResource** | Educational content for teams | `programId`, `title`, `description`, `contentJson`, `resourceType`, `cohortLevel`, `fileName`, `mimeType`, `bucket`, `objectKey`, `externalUrl`, `isPublished` | → Program?, → User (creator), → ResourceAccess[] |
| **ResourceAccess** | Access log for learning materials | `resourceId`, `userId`, `accessedAt`, `ipAddress` | → LearningResource, → User |
| **Partner** | Sponsor/partner organization | `programId`, `name`, `description`, `website`, `partnerType`, `visibility`, `logoFileName`, `sortOrder`, `isActive` | → Program? |
| **WizardTemplate** | Saved pipeline configuration templates | `name`, `description`, `config`, `isGlobal`, `programId`, `createdBy` | → Program?, → User |

### 1.11 Communication Models

| Model | Purpose | Key Fields | Relations |
|-------|---------|------------|-----------|
| **InAppNotification** | Bell icon notifications | `userId`, `type`, `priority`, `icon`, `title`, `message`, `linkUrl`, `linkLabel`, `metadata`, `groupKey`, `isRead`, `expiresAt` | → User |
| **NotificationEmailSetting** | Email notification toggles per type | `notificationType`, `category`, `label`, `sendEmail`, `emailSubject`, `emailTemplate` | (standalone) |
| **NotificationPolicy** | Event-driven notification config | `eventType`, `channel`, `templateId`, `isActive`, `configJson` | (no FK relations) |
| **Message** | Bulk messaging system | `senderId`, `recipientType`, `recipientFilter`, `stageId`, `templateId`, `subject`, `body`, `deliveryChannels`, `scheduledAt`, `sentAt` | → User (sender), → Stage?, → MessageTemplate?, → MessageRecipient[] |
| **MessageRecipient** | Individual message delivery | `messageId`, `userId`, `channel`, `isRead`, `readAt`, `deliveredAt` | → Message, → User |
| **MessageTemplate** | Reusable email templates | `name`, `category`, `subject`, `body`, `variables`, `isActive`, `createdBy` | → User, ← Message[] |

### 1.12 Webhooks & Integrations

| Model | Purpose | Key Fields | Relations |
|-------|---------|------------|-----------|
| **Webhook** | Outbound event webhooks | `name`, `url`, `secret`, `events`, `headers`, `maxRetries`, `isActive`, `createdById` | → User, → WebhookDelivery[] |
| **WebhookDelivery** | Webhook delivery log | `webhookId`, `event`, `payload`, `status`, `responseStatus`, `responseBody`, `attempts`, `lastAttemptAt` | → Webhook |

### 1.13 Miscellaneous Models

| Model | Purpose | Key Fields | Relations |
|-------|---------|------------|-----------|
| **SystemSettings** | Platform-wide config KV store | `key`, `value`, `type`, `category`, `description`, `isSecret` | (standalone) |
| **ExpertiseTag** | Tag taxonomy for matching | `name`, `description`, `category`, `color`, `isActive`, `sortOrder` | → ProjectTag[] |
| **ProjectTag** | Project-tag association | `projectId`, `tagId`, `confidence`, `source` | → Project, → ExpertiseTag |
| **ProjectStatusHistory** | Historical status changes | `projectId`, `status`, `changedAt`, `changedBy` | → Project |
| **ReminderLog** | Evaluation deadline reminders | `stageId`, `userId`, `type`, `sentAt` | → Stage, → User |
| **DigestLog** | Email digest delivery log | `userId`, `digestType`, `contentJson`, `sentAt` | → User |

---

## 2. Enums

### 2.1 User & Auth Enums

| Enum | Values | Usage |
|------|--------|-------|
| **UserRole** | `SUPER_ADMIN`, `PROGRAM_ADMIN`, `JURY_MEMBER`, `MENTOR`, `OBSERVER`, `APPLICANT`, `AWARD_MASTER`, `AUDIENCE` | User permissions hierarchy |
| **UserStatus** | `NONE`, `INVITED`, `ACTIVE`, `SUSPENDED` | User account state |

### 2.2 Project & Competition Enums

| Enum | Values | Usage |
|------|--------|-------|
| **ProjectStatus** | `SUBMITTED`, `ELIGIBLE`, `ASSIGNED`, `SEMIFINALIST`, `FINALIST`, `REJECTED` | Legacy project state (superseded by ProjectStageState) |
| **CompetitionCategory** | `STARTUP`, `BUSINESS_CONCEPT` | Project type (existing company vs. student idea) |
| **OceanIssue** | `POLLUTION_REDUCTION`, `CLIMATE_MITIGATION`, `TECHNOLOGY_INNOVATION`, `SUSTAINABLE_SHIPPING`, `BLUE_CARBON`, `HABITAT_RESTORATION`, `COMMUNITY_CAPACITY`, `SUSTAINABLE_FISHING`, `CONSUMER_AWARENESS`, `OCEAN_ACIDIFICATION`, `OTHER` | Project focus area |

### 2.3 Pipeline Enums

| Enum | Values | Usage |
|------|--------|-------|
| **StageType** | `INTAKE`, `FILTER`, `EVALUATION`, `SELECTION`, `LIVE_FINAL`, `RESULTS` | Stage functional type |
| **TrackKind** | `MAIN`, `AWARD`, `SHOWCASE` | Track purpose |
| **RoutingMode** | `SHARED`, `EXCLUSIVE` | Project routing behavior (can projects be in multiple tracks?) |
| **StageStatus** | `STAGE_DRAFT`, `STAGE_ACTIVE`, `STAGE_CLOSED`, `STAGE_ARCHIVED` | Stage lifecycle state |
| **ProjectStageStateValue** | `PENDING`, `IN_PROGRESS`, `PASSED`, `REJECTED`, `ROUTED`, `COMPLETED`, `WITHDRAWN` | Project state within a stage |
| **DecisionMode** | `JURY_VOTE`, `AWARD_MASTER_DECISION`, `ADMIN_DECISION` | How winners are determined in a track |

### 2.4 Evaluation & Assignment Enums

| Enum | Values | Usage |
|------|--------|-------|
| **EvaluationStatus** | `NOT_STARTED`, `DRAFT`, `SUBMITTED`, `LOCKED` | Evaluation completion state |
| **AssignmentMethod** | `MANUAL`, `BULK`, `AI_SUGGESTED`, `AI_AUTO`, `ALGORITHM` | How assignment was created |
| **MentorAssignmentMethod** | `MANUAL`, `AI_SUGGESTED`, `AI_AUTO`, `ALGORITHM` | How mentor was paired |

### 2.5 Filtering Enums

| Enum | Values | Usage |
|------|--------|-------|
| **FilteringOutcome** | `PASSED`, `FILTERED_OUT`, `FLAGGED` | Filtering result |
| **FilteringRuleType** | `FIELD_BASED`, `DOCUMENT_CHECK`, `AI_SCREENING` | Type of filtering rule |
| **FilteringJobStatus** | `PENDING`, `RUNNING`, `COMPLETED`, `FAILED` | Job progress state |
| **AssignmentJobStatus** | `PENDING`, `RUNNING`, `COMPLETED`, `FAILED` | Job progress state |
| **TaggingJobStatus** | `PENDING`, `RUNNING`, `COMPLETED`, `FAILED` | Job progress state |

### 2.6 Awards Enums

| Enum | Values | Usage |
|------|--------|-------|
| **AwardScoringMode** | `PICK_WINNER`, `RANKED`, `SCORED` | Award voting method |
| **AwardStatus** | `DRAFT`, `NOMINATIONS_OPEN`, `VOTING_OPEN`, `CLOSED`, `ARCHIVED` | Award lifecycle |
| **EligibilityMethod** | `AUTO`, `MANUAL` | How eligibility was determined |

### 2.7 Miscellaneous Enums

| Enum | Values | Usage |
|------|--------|-------|
| **FileType** | `EXEC_SUMMARY`, `PRESENTATION`, `VIDEO`, `OTHER`, `BUSINESS_PLAN`, `VIDEO_PITCH`, `SUPPORTING_DOC` | Project file categorization |
| **SubmissionSource** | `MANUAL`, `CSV`, `NOTION`, `TYPEFORM`, `PUBLIC_FORM` | How project was submitted |
| **NotificationChannel** | `EMAIL`, `WHATSAPP`, `BOTH`, `NONE` | Notification delivery method |
| **ResourceType** | `PDF`, `VIDEO`, `DOCUMENT`, `LINK`, `OTHER` | Learning resource type |
| **CohortLevel** | `ALL`, `SEMIFINALIST`, `FINALIST` | Access level for resources |
| **PartnerVisibility** | `ADMIN_ONLY`, `JURY_VISIBLE`, `PUBLIC` | Who can see partner |
| **PartnerType** | `SPONSOR`, `PARTNER`, `SUPPORTER`, `MEDIA`, `OTHER` | Partner categorization |
| **TeamMemberRole** | `LEAD`, `MEMBER`, `ADVISOR` | Team composition |
| **OverrideReasonCode** | `DATA_CORRECTION`, `POLICY_EXCEPTION`, `JURY_CONFLICT`, `SPONSOR_DECISION`, `ADMIN_DISCRETION` | Why decision was overridden |
| **ProgramStatus** | `DRAFT`, `ACTIVE`, `ARCHIVED` | Program lifecycle |
| **SettingType** | `STRING`, `NUMBER`, `BOOLEAN`, `JSON`, `SECRET` | System setting data type |
| **SettingCategory** | `AI`, `BRANDING`, `EMAIL`, `STORAGE`, `SECURITY`, `DEFAULTS`, `WHATSAPP`, `AUDIT_CONFIG`, `LOCALIZATION`, `DIGEST`, `ANALYTICS`, `INTEGRATIONS`, `COMMUNICATION` | Setting organization |

---

## 3. Services

All services located in `src/server/services/*.ts`.

| Service | Purpose | Key Functions |
|---------|---------|---------------|
| **stage-engine.ts** | State machine for project transitions | `validateTransition()`, `executeTransition()`, `executeBatchTransition()` - handles guard evaluation, atomic PSS updates, audit logging |
| **stage-filtering.ts** | Runs filtering pipeline scoped to stage | `runStageFiltering()`, `resolveManualDecision()`, `getManualQueue()` - executes field-based, document, and AI rules; duplicate detection built-in |
| **stage-assignment.ts** | Smart jury assignment generation | `previewStageAssignment()`, `executeStageAssignment()`, `getCoverageReport()`, `rebalance()` - tag matching, workload balancing, COI handling |
| **stage-notifications.ts** | Event-driven notification producer | `emitStageEvent()`, `onStageTransitioned()`, `onFilteringCompleted()`, `onAssignmentGenerated()`, `onCursorUpdated()` - never throws, creates DecisionAuditLog + in-app + email |
| **live-control.ts** | Real-time live ceremony control | `startSession()`, `setActiveProject()`, `jumpToProject()`, `reorderQueue()`, `pauseResume()`, `openCohortWindow()`, `closeCohortWindow()` - manages LiveProgressCursor |
| **ai-filtering.ts** | AI-powered project screening | Anonymizes data, calls OpenAI API, confidence banding, spam detection (delegates to stage-filtering.ts for execution) |
| **ai-assignment.ts** | AI-suggested jury matching | GPT-based assignment generation with expertise matching (100 lines) |
| **ai-evaluation-summary.ts** | GPT synthesis of evaluations | Generates strengths/weaknesses summary from jury feedback |
| **ai-tagging.ts** | Automatic project categorization | Tags projects with expertise areas using GPT |
| **ai-award-eligibility.ts** | Award eligibility assessment | GPT determines if project meets award criteria |
| **anonymization.ts** | GDPR-compliant data stripping | Removes PII before AI calls (name, email, institution, etc.) |
| **ai-errors.ts** | Centralized AI error handling | Classifies errors (rate limit, token limit, API down), provides retry logic |
| **award-eligibility-job.ts** | Batch award eligibility processing | Runs AI eligibility checks across all projects for an award |
| **smart-assignment.ts** | Scoring algorithm for matching | Tag overlap, bio match, workload balance, geo diversity, COI blocking, availability checking |
| **mentor-matching.ts** | Mentor-project pairing logic | Similar to smart-assignment but for mentorship |
| **evaluation-reminders.ts** | Cron job for deadline reminders | Sends 3-day, 24h, 1h reminders to jury with incomplete evaluations |
| **email-digest.ts** | Daily/weekly email summaries | Aggregates pending tasks for users |
| **in-app-notification.ts** | In-app notification helpers | Creates bell-icon notifications with linking |
| **notification.ts** | Email sending service | Wraps Nodemailer, supports templates |
| **webhook-dispatcher.ts** | Webhook delivery service | Sends events to registered webhook URLs with retry logic |

---

## 4. tRPC Routers

All routers located in `src/server/routers/*.ts`. Total: 38 routers.

| Router | Procedure Count | Key Procedures | Purpose |
|--------|-----------------|----------------|---------|
| **pipeline.ts** | ~15 | `create`, `update`, `delete`, `list`, `getById`, `archive` | Pipeline CRUD, linking to Program |
| **stage.ts** | ~20 | `create`, `updateConfig`, `updateStatus`, `delete`, `getByTrack`, `reorderStages`, `createTransition` | Stage CRUD, window management, transition setup |
| **stageFiltering.ts** | ~10 | `createRule`, `runFiltering`, `getManualQueue`, `resolveManualDecision`, `getJobStatus` | Filtering rule management + execution |
| **stageAssignment.ts** | ~8 | `previewAssignment`, `executeAssignment`, `getCoverage`, `rebalance`, `bulkDelete` | Assignment generation, coverage analysis |
| **project.ts** | ~25 | `create`, `update`, `delete`, `getById`, `list`, `import`, `advanceToRound`, `updateStatus` | Project CRUD, CSV import, status changes |
| **assignment.ts** | ~12 | `create`, `bulkCreate`, `delete`, `getByUser`, `getByProject`, `markComplete` | Manual assignment management |
| **evaluation.ts** | ~15 | `create`, `update`, `submit`, `lock`, `unlock`, `getByAssignment`, `generateSummary` | Evaluation submission, locking |
| **gracePeriod.ts** | ~6 | `create`, `delete`, `getByStage`, `getByUser`, `checkActive` | Grace period management |
| **user.ts** | ~20 | `create`, `update`, `delete`, `invite`, `resendInvite`, `list`, `updateProfile`, `uploadAvatar` | User management, invites |
| **specialAward.ts** | ~15 | `create`, `update`, `delete`, `runEligibility`, `vote`, `getResults`, `overrideWinner` | Award creation, voting, eligibility |
| **live-voting.ts** | ~12 | `createSession`, `vote`, `getResults`, `closeSession`, `updateCriteria` | Live voting session management (legacy LiveVotingSession model) |
| **live.ts** | ~10 | `startSession`, `setActiveProject`, `jumpToProject`, `pauseResume`, `openCohort`, `closeCohort` | Live control (new LiveProgressCursor model) |
| **cohort.ts** | ~8 | `create`, `update`, `delete`, `addProjects`, `removeProjects`, `reorder` | Cohort management for live finals |
| **mentor.ts** | ~12 | `assignMentor`, `removeMentor`, `sendMessage`, `addNote`, `completeMilestone`, `getMentorDashboard` | Mentorship workflow |
| **learningResource.ts** | ~10 | `create`, `update`, `delete`, `list`, `upload`, `markAccessed` | Learning hub content |
| **partner.ts** | ~8 | `create`, `update`, `delete`, `list`, `uploadLogo` | Partner management |
| **tag.ts** | ~10 | `create`, `update`, `delete`, `list`, `runTagging`, `getTaggingJobStatus` | Expertise tag management |
| **notification.ts** | ~8 | `getInApp`, `markRead`, `markAllRead`, `getUnreadCount`, `updateEmailSettings` | Notification center |
| **message.ts** | ~10 | `send`, `schedule`, `list`, `getRecipients`, `createTemplate`, `listTemplates` | Bulk messaging |
| **webhook.ts** | ~8 | `create`, `update`, `delete`, `test`, `getDeliveries`, `retry` | Webhook management |
| **audit.ts** | ~6 | `getAuditLog`, `getDecisionLog`, `getOverrides`, `export` | Audit trail viewing |
| **analytics.ts** | ~12 | `getDashboardStats`, `getProjectStats`, `getJuryStats`, `getAwardStats`, `getEngagementMetrics` | Reporting and analytics |
| **dashboard.ts** | ~8 | `getAdminDashboard`, `getJuryDashboard`, `getApplicantDashboard`, `getMentorDashboard` | Role-specific dashboards |
| **export.ts** | ~8 | `exportProjects`, `exportEvaluations`, `exportVotes`, `exportAuditLog` | CSV/Excel exports |
| **file.ts** | ~8 | `uploadFile`, `getPresignedUrl`, `deleteFile`, `listFiles`, `createRequirement` | MinIO file management |
| **filtering.ts** | ~6 | Legacy filtering endpoints (superseded by stageFiltering) | Deprecated |
| **avatar.ts** | ~4 | `upload`, `delete`, `getUrl` | User profile images |
| **logo.ts** | ~4 | `upload`, `delete`, `getUrl` | Project logos |
| **decision.ts** | ~6 | `overrideFilteringResult`, `overrideAwardEligibility`, `overridePSS`, `getOverrideHistory` | Admin override controls |
| **program.ts** | ~10 | `create`, `update`, `delete`, `list`, `getById`, `archive` | Program CRUD |
| **application.ts** | ~8 | `submitApplication`, `saveDraft`, `getDraft`, `deleteDraft` | Public application form |
| **applicant.ts** | ~10 | `getMyProjects`, `updateTeam`, `uploadDocument`, `requestMentorship` | Applicant portal |
| **notion-import.ts** | ~4 | `sync`, `import`, `getStatus` | Notion integration |
| **typeform-import.ts** | ~4 | `sync`, `import`, `getStatus` | Typeform integration |
| **settings.ts** | ~8 | `get`, `set`, `getBulk`, `setBulk`, `getByCategory` | System settings KV store |
| **project-pool.ts** | ~6 | `getUnassignedProjects`, `getProjectsByStage`, `getProjectsByStatus` | Project queries for assignment |
| **wizard-template.ts** | ~8 | `create`, `update`, `delete`, `list`, `clone`, `applyTemplate` | Pipeline wizard templates |

**Total Procedures:** ~400+

---

## 5. UI Pages

### 5.1 Admin Pages (`src/app/(admin)/admin/`)

| Route | Purpose | Key Features |
|-------|---------|--------------|
| `/admin` | Admin dashboard | Overview metrics, recent activity, quick actions |
| `/admin/members` | User management list | User table with filters, role assignment, status changes |
| `/admin/members/[id]` | User detail/edit | Profile editing, role changes, assignment history |
| `/admin/members/invite` | Invite new users | Bulk invite form with role selection |
| `/admin/programs` | Program list | Program cards, create/archive/edit |
| `/admin/programs/[id]` | Program detail | Program overview, linked pipelines, projects |
| `/admin/programs/[id]/edit` | Program settings editor | Name, year, status, settingsJson editor |
| `/admin/programs/[id]/apply-settings` | Application form config | Public submission form customization |
| `/admin/programs/[id]/mentorship` | Mentorship milestones | Milestone creation, completion tracking |
| `/admin/projects` | Project list | Searchable/filterable project table |
| `/admin/projects/[id]` | Project detail | Full project view with evaluations, history |
| `/admin/projects/[id]/edit` | Project editor | Edit project metadata, team, tags |
| `/admin/projects/[id]/mentor` | Mentor assignment | Assign/remove mentor, view messages |
| `/admin/projects/new` | Manual project creation | Add project without public form |
| `/admin/projects/import` | CSV/Typeform/Notion import | Bulk import wizard |
| `/admin/projects/pool` | Unassigned project pool | Projects awaiting assignment |
| `/admin/rounds/pipelines` | Pipeline list | All pipelines across programs |
| `/admin/rounds/pipeline/[id]` | Pipeline detail | Track/stage tree, project flow diagram |
| `/admin/rounds/pipeline/[id]/edit` | Pipeline settings | Name, slug, status, settingsJson |
| `/admin/rounds/pipeline/[id]/wizard` | Pipeline wizard | Step-by-step configuration UI (tracks, stages, transitions) |
| `/admin/rounds/pipeline/[id]/advanced` | Advanced pipeline editor | JSON config editor, raw transitions |
| `/admin/rounds/new-pipeline` | Pipeline creation wizard | Multi-step pipeline setup |
| `/admin/awards` | Special awards list | Award cards with status |
| `/admin/awards/[id]` | Award detail | Eligibility, votes, results |
| `/admin/awards/[id]/edit` | Award editor | Criteria, voting config, jury panel |
| `/admin/awards/new` | Create award | Award creation form |
| `/admin/mentors` | Mentor list | All users with MENTOR role |
| `/admin/mentors/[id]` | Mentor detail | Assigned projects, notes, milestones |
| `/admin/learning` | Learning hub management | Resource list, upload, publish |
| `/admin/learning/[id]` | Resource detail/edit | Content editor (BlockNote), access logs |
| `/admin/learning/new` | Create resource | Upload or link external content |
| `/admin/partners` | Partner management | Partner list, logos, visibility |
| `/admin/partners/[id]` | Partner detail/edit | Edit partner info, upload logo |
| `/admin/partners/new` | Add partner | Partner creation form |
| `/admin/messages` | Messaging dashboard | Send bulk messages, view sent messages |
| `/admin/messages/templates` | Message templates | Template CRUD |
| `/admin/settings` | System settings | Category tabs, KV editor |
| `/admin/settings/tags` | Expertise tags | Tag taxonomy management |
| `/admin/settings/webhooks` | Webhook management | Webhook CRUD, delivery logs |
| `/admin/audit` | Audit log viewer | Searchable audit trail |
| `/admin/reports` | Analytics reports | Charts, exports, metrics |
| `/admin/reports/stages` | Stage-level reports | Per-stage assignment coverage, completion rates |

### 5.2 Jury Pages (`src/app/(jury)/jury/`)

| Route | Purpose | Key Features |
|-------|---------|--------------|
| `/jury` | Jury dashboard | Assigned stages, pending evaluations, deadlines |
| `/jury/stages` | Jury stage list | Stages where user has assignments |
| `/jury/stages/[stageId]/assignments` | Assignment list for stage | Projects assigned to this user |
| `/jury/stages/[stageId]/projects/[projectId]` | Project detail view | Full project info, files, team |
| `/jury/stages/[stageId]/projects/[projectId]/evaluate` | Evaluation form | Criterion scoring, feedback, submit |
| `/jury/stages/[stageId]/projects/[projectId]/evaluation` | View submitted evaluation | Read-only evaluation, edit if not locked |
| `/jury/stages/[stageId]/compare` | Side-by-side comparison | Compare multiple projects, scoring matrix |
| `/jury/stages/[stageId]/live` | Live voting interface | Real-time voting during live ceremony |
| `/jury/awards` | Special awards list | Awards where user is juror |
| `/jury/awards/[id]` | Award voting | View eligible projects, cast votes |
| `/jury/learning` | Learning hub (jury access) | Resources for jury members |

### 5.3 Applicant Pages (`src/app/(applicant)/applicant/`)

| Route | Purpose | Key Features |
|-------|---------|--------------|
| `/applicant` | Applicant dashboard | Application status, next steps |
| `/applicant/pipeline` | Pipeline progress view | Visual pipeline with current stage |
| `/applicant/pipeline/[stageId]/status` | Stage detail view | Stage status, requirements, deadlines |
| `/applicant/pipeline/[stageId]/documents` | Document upload | Upload required files for stage |
| `/applicant/documents` | All documents | Document library, versions |
| `/applicant/team` | Team management | Add/remove team members, roles |
| `/applicant/mentor` | Mentorship dashboard | Chat with mentor, milestones |

### 5.4 Auth Pages (`src/app/(auth)/`)

| Route | Purpose | Key Features |
|-------|---------|--------------|
| `/login` | Login page | Email magic link + password login |
| `/verify` | Magic link verification | Token verification, auto-login |
| `/verify-email` | Email verification | Verify email after signup |
| `/accept-invite` | Invitation acceptance | One-click invite token handling |
| `/set-password` | Password setup | First-time password creation |
| `/onboarding` | User onboarding wizard | Profile completion, expertise tags |
| `/error` | Auth error page | Error display with retry |

---

## 6. Strengths of Current System

### 6.1 Architecture Strengths

| Strength | Description |
|----------|-------------|
| **Full Type Safety** | End-to-end TypeScript from DB → tRPC → React. Prisma generates types, tRPC enforces them, components consume them safely. |
| **Atomic Transactions** | All critical operations (stage transitions, filtering, assignments) use `$transaction` with proper rollback. |
| **Comprehensive Audit** | Dual audit system: `AuditLog` for general activity, `DecisionAuditLog` for pipeline decisions. Full traceability. |
| **RBAC Enforcement** | tRPC middleware hierarchy (`adminProcedure`, `juryProcedure`, etc.) enforces role-based access at API level. |
| **GDPR Compliance** | All AI calls strip PII via `anonymization.ts`. No personal data sent to OpenAI. |
| **Event-Driven Design** | `stage-notifications.ts` emits events on every pipeline action. Notifications never block core operations (catch all errors). |
| **Graceful AI Error Handling** | `ai-errors.ts` classifies errors (rate limit, token limit, API down) and provides retry guidance. AI failures never crash the system. |
| **Duplicate Detection** | Built-in duplicate submission detection in `stage-filtering.ts` (by email). Always flags for manual review, never auto-rejects. |

### 6.2 Data Model Strengths

| Strength | Description |
|----------|-------------|
| **Flexible Pipeline Model** | Pipeline → Track → Stage → ProjectStageState allows arbitrary round structures. Main track + multiple award tracks supported. |
| **Guard-Based Transitions** | StageTransition `guardJson` field allows complex conditional routing (e.g., "only advance if avgScore >= 7"). |
| **Stage Config Polymorphism** | `Stage.configJson` adapts to `stageType`. FILTER stages have filtering config, EVALUATION stages have evaluation config, etc. |
| **Versioned Evaluations** | `Evaluation.version` field allows rollback (though not currently used). |
| **Override Audit Trail** | `OverrideAction` model logs all admin overrides with reason codes. Immutable audit. |

### 6.3 Service Layer Strengths

| Strength | Description |
|----------|-------------|
| **State Machine Isolation** | `stage-engine.ts` is the ONLY service that modifies `ProjectStageState`. All transitions go through it. Single source of truth. |
| **Service Purity** | Services are pure functions that accept Prisma client as parameter. Testable without mocking globals. |
| **Progress Tracking** | Long-running operations (filtering, assignment, tagging) use Job models (`FilteringJob`, `AssignmentJob`, `TaggingJob`) for progress tracking. |
| **AI Batching** | All AI services batch projects (20-50 per call) to reduce API cost and latency. |

### 6.4 UX Strengths

| Strength | Description |
|----------|-------------|
| **Wizard-Driven Setup** | Pipeline wizard (`/admin/rounds/pipeline/[id]/wizard`) guides admins through complex configuration. |
| **Real-Time Live Control** | `/jury/stages/[stageId]/live` provides live voting with cursor sync via `LiveProgressCursor`. |
| **Notification Center** | In-app notification bell with grouping, priorities, expiration. |
| **Grace Period UX** | Admins can grant individual deadline extensions with reason tracking. |
| **Filtering Manual Queue** | Flagged projects go to dedicated review queue (`/admin/rounds/pipeline/[id]/filtering/manual`) for admin decision. |

---

## 7. Weaknesses of Current System

### 7.1 Data Model Issues

| Issue | Description | Impact |
|-------|-------------|--------|
| **Legacy `roundId` Fields** | 50+ models have `roundId String?` (marked "Legacy — kept for historical data"). Adds noise, not enforced. | Confusing for new developers. No FK constraints. |
| **Unclear Pipeline Lifecycle** | Pipeline has `status` enum (`DRAFT`, `ACTIVE`, `ARCHIVED`), but no enforcement. Active pipelines can have draft stages. | Inconsistent state possible. |
| **Overlapping Voting Models** | `LiveVotingSession` (old) and `Cohort` + `LiveProgressCursor` (new) both exist. Unclear which to use. | Duplicate functionality, confusion. |
| **No PSS Validation Constraints** | `ProjectStageState` allows multiple active (non-exited) records for same project/track/stage combo. Should be unique. | Data integrity risk. |
| **Track-Award Linkage Vague** | `SpecialAward.trackId` is optional. Unclear if awards MUST have a track or can exist independently. | Ambiguous design. |

### 7.2 Service Layer Issues

| Issue | Description | Impact |
|-------|-------------|--------|
| **Mixed Abstraction Levels** | `stage-filtering.ts` contains both high-level orchestration AND low-level rule evaluation. Hard to test individually. | Tight coupling. |
| **Notification Side Effects** | Services call `stage-notifications.ts` directly. If notification fails (e.g., email down), error is swallowed. | Lost notifications, no visibility. |
| **AI Service Duplication** | `ai-filtering.ts`, `ai-assignment.ts`, `ai-tagging.ts` all have similar batching/retry logic. Should be abstracted. | Code duplication. |
| **No Explicit Workflow Engine** | Stage transitions are ad-hoc. No central workflow definition. Must read code to understand flow. | Hard to visualize, modify. |

### 7.3 tRPC Router Issues

| Issue | Description | Impact |
|-------|-------------|--------|
| **Router Bloat** | `project.ts` has 25+ procedures. `user.ts` has 20+. Hard to navigate. | Monolithic routers. |
| **Inconsistent Naming** | `stage.ts` has `updateConfig`, `stage-filtering.ts` router has `updateRule`. Naming conventions vary. | Confusing API. |
| **No Batch Procedures** | Most CRUD operations are one-at-a-time. No bulk create/update/delete (except assignments). | N+1 queries in UI. |
| **Missing Pagination** | List procedures (`project.list`, `user.list`) return all records. No cursor or offset pagination. | Performance issue at scale. |

### 7.4 UI/UX Issues

| Issue | Description | Impact |
|-------|-------------|--------|
| **No Pipeline Visualization** | Pipeline detail page shows table of stages, not a flowchart. Hard to see transitions. | Poor admin UX. |
| **Filtering Manual Queue Hidden** | Flagged projects not prominently surfaced. Admin must navigate deep into pipeline detail. | Flagged items forgotten. |
| **No Bulk Actions** | Can't bulk-assign projects, bulk-approve evaluations, bulk-transition projects. Must click one-by-one. | Tedious admin work. |
| **Live Voting Lacks Feedback** | Jury votes during live event but doesn't see if vote was counted. No confirmation toast. | Uncertainty. |
| **No Undo** | All admin actions (delete pipeline, archive stage, reject project) are immediate. No soft delete or undo. | Risky operations. |

### 7.5 Missing Features

| Missing Feature | Description | Impact |
|-----------------|-------------|--------|
| **Stage Dependency Graph** | No visual representation of stage transitions and guards. Admin must infer from transitions table. | Hard to debug routing. |
| **Evaluation Calibration** | No juror calibration (e.g., flag jurors who score 10x higher/lower than peers). | Scoring bias undetected. |
| **Award Winner Tie-Breaking** | `SpecialAward.tieBreakerMethod` exists in `LiveVotingSession` but not in `SpecialAward`. No tie resolution for ranked awards. | Undefined behavior on ties. |
| **Project Search Ranking** | Project search is basic string match. No relevance ranking, fuzzy matching, or faceted filters. | Poor search UX. |
| **Stage Templates** | No template system for common stage configs (e.g., "Standard 3-juror evaluation stage"). | Repetitive setup. |
| **Notification Preferences** | Users can toggle email on/off globally but not per event type. No granular control. | All-or-nothing notifications. |
| **Pipeline Cloning** | No way to duplicate a pipeline for a new year/program. Must recreate manually. | Time-consuming setup. |
| **Evaluation Rubric Library** | Each stage creates evaluation forms from scratch. No reusable rubrics. | Reinventing the wheel. |

### 7.6 Code Quality Issues

| Issue | Description | Impact |
|-------|-------------|--------|
| **Inconsistent Error Messages** | Some procedures throw `TRPCError` with clear messages, others just throw generic Error. | Debugging harder. |
| **No Input Sanitization** | Zod validates types but doesn't trim strings, lowercase emails, etc. | Data inconsistency. |
| **Magic Numbers** | Hardcoded constants (e.g., `AI_CONFIDENCE_THRESHOLD_PASS = 0.75`) scattered across services. | Hard to tune. |
| **Limited Test Coverage** | Only `stage-engine.test.ts` exists. No tests for filtering, assignment, AI services. | Regression risk. |
| **No API Versioning** | tRPC routers have no version prefix. Breaking changes would break old clients. | API fragility. |

### 7.7 Performance Issues

| Issue | Description | Impact |
|-------|-------------|--------|
| **N+1 Queries** | Project list page loads projects, then fetches assignments for each in a loop. | Slow page load. |
| **No Caching** | Every tRPC call hits database. No Redis, no in-memory cache. | High DB load. |
| **Unindexed Joins** | Some `ProjectStageState` queries join on `(projectId, trackId)` without composite index. | Slow at scale. |
| **AI Batching Non-Optimal** | AI services batch by count (20 projects) not by token size. Large projects can exceed token limits. | API errors. |

### 7.8 Documentation Issues

| Issue | Description | Impact |
|-------|-------------|--------|
| **No Architecture Docs** | No high-level system overview. New developers must read code. | Steep onboarding. |
| **Minimal JSDoc** | Most services have file-level comments but not function-level. | Hard to use without reading implementation. |
| **No API Reference** | tRPC procedures not documented in OpenAPI or similar. | Client integration difficult. |
| **No Runbook** | No operational docs for common tasks (e.g., "How to fix a stuck pipeline"). | Manual troubleshooting. |

---

## Summary Statistics

| Category | Count |
|----------|-------|
| **Database Models** | 73 |
| **Enums** | 31 |
| **Service Files** | 20 |
| **tRPC Routers** | 38 |
| **tRPC Procedures** | ~400 |
| **Admin Pages** | 45 |
| **Jury Pages** | 11 |
| **Applicant Pages** | 7 |
| **Auth Pages** | 7 |
| **Total Distinct Routes** | ~70 |

---

## Appendix: Service Function Inventory

### stage-engine.ts
- `evaluateGuardCondition()` - Evaluates a single guard condition
- `evaluateGuard()` - Evaluates guard config with AND/OR logic
- `validateTransition()` - Checks if transition is allowed (PSS exists, transition defined, stage active, window open, guards pass)
- `executeTransition()` - Atomically transitions a project between stages (exits source PSS, creates/updates dest PSS, logs in DecisionAuditLog + AuditLog)
- `executeBatchTransition()` - Batch wrapper around executeTransition (processes 50 at a time)

### stage-filtering.ts
- `evaluateFieldCondition()` - Evaluates a single field-based rule condition
- `evaluateFieldRule()` - Evaluates field-based rule with AND/OR logic
- `evaluateDocumentCheck()` - Checks if project has required files
- `bandByConfidence()` - AI confidence thresholding (0.75+ = PASSED, 0.25- = FILTERED_OUT, else FLAGGED)
- `runStageFiltering()` - Main orchestration: loads projects, rules, runs deterministic then AI, saves FilteringResults, creates FilteringJob
- `resolveManualDecision()` - Admin resolves a FLAGGED result to PASSED or FILTERED_OUT, logs override
- `getManualQueue()` - Returns all FLAGGED results for a stage

### stage-assignment.ts
- `calculateTagOverlapScore()` - Counts matching tags between juror and project (max 40 points)
- `calculateWorkloadScore()` - Scores juror based on current load vs preferred (max 25 points)
- `previewStageAssignment()` - Dry run: scores all juror-project pairs, returns top N per project
- `executeStageAssignment()` - Creates Assignment records, logs in AssignmentJob
- `getCoverageReport()` - Returns per-project review counts, per-juror assignment counts
- `rebalance()` - Identifies overloaded/underloaded jurors, suggests reassignments

### stage-notifications.ts
- `emitStageEvent()` - Core event producer: creates DecisionAuditLog, checks NotificationPolicy, creates InAppNotification, sends email (never throws)
- `resolveRecipients()` - Determines who gets notified based on event type (admins, jury, etc.)
- `buildNotificationMessage()` - Builds human-readable message from event details
- `onStageTransitioned()` - Convenience wrapper for stage.transitioned event
- `onFilteringCompleted()` - Convenience wrapper for filtering.completed event
- `onAssignmentGenerated()` - Convenience wrapper for assignment.generated event
- `onCursorUpdated()` - Convenience wrapper for live.cursor_updated event
- `onDecisionOverridden()` - Convenience wrapper for decision.overridden event

### live-control.ts
- `generateSessionId()` - Creates unique session ID (timestamp + random)
- `startSession()` - Creates/resets LiveProgressCursor, sets first project active
- `setActiveProject()` - Updates cursor to point to a specific project (validates project is in cohort)
- `jumpToProject()` - Jumps to project by order index
- `reorderQueue()` - Updates CohortProject sortOrder values in batch
- `pauseResume()` - Toggles cursor pause state
- `openCohortWindow()` - Opens voting window for a cohort (sets isOpen=true, windowOpenAt=now)
- `closeCohortWindow()` - Closes voting window for a cohort (sets isOpen=false, windowCloseAt=now)

---

**End of Document**
