45 KiB
45 KiB
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.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 conditionevaluateGuard()- Evaluates guard config with AND/OR logicvalidateTransition()- 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 conditionevaluateFieldRule()- Evaluates field-based rule with AND/OR logicevaluateDocumentCheck()- Checks if project has required filesbandByConfidence()- 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 FilteringJobresolveManualDecision()- Admin resolves a FLAGGED result to PASSED or FILTERED_OUT, logs overridegetManualQueue()- 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 projectexecuteStageAssignment()- Creates Assignment records, logs in AssignmentJobgetCoverageReport()- Returns per-project review counts, per-juror assignment countsrebalance()- 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 detailsonStageTransitioned()- Convenience wrapper for stage.transitioned eventonFilteringCompleted()- Convenience wrapper for filtering.completed eventonAssignmentGenerated()- Convenience wrapper for assignment.generated eventonCursorUpdated()- Convenience wrapper for live.cursor_updated eventonDecisionOverridden()- Convenience wrapper for decision.overridden event
live-control.ts
generateSessionId()- Creates unique session ID (timestamp + random)startSession()- Creates/resets LiveProgressCursor, sets first project activesetActiveProject()- Updates cursor to point to a specific project (validates project is in cohort)jumpToProject()- Jumps to project by order indexreorderQueue()- Updates CohortProject sortOrder values in batchpauseResume()- Toggles cursor pause stateopenCohortWindow()- 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