11 KiB
Executive Summary: MOPC Architecture Redesign
Why This Redesign
The MOPC platform currently uses a Pipeline -> Track -> Stage model with generic JSON configs to orchestrate the competition. While technically sound, this architecture introduces unnecessary abstraction for what is fundamentally a linear sequential competition flow.
Current Problems
| Problem | Impact |
|---|---|
| 3-level nesting (Pipeline->Track->Stage) | Cognitive overhead for admins configuring rounds |
Generic configJson blobs per stage type |
"Vague" — hard to know what's configurable without reading code |
| No explicit jury entities | Juries are implicit (per-stage assignments), can't manage "Jury 1" as a thing |
| Single submission round | No way to open a second submission window for semi-finalists |
| Track layer for main flow | MAIN track adds indirection without value for a linear flow |
| No mentoring workspace | Mentor file exchange exists but no comments, no promotion to submission |
| No winner confirmation | No multi-party agreement step to cement winners |
| Missing round types | Can't model a "Semi-finalist Submission" or "Mentoring" or "Confirmation" step |
Design Principles
- Domain over abstraction — Models map directly to competition concepts (Jury 1, Round 2, etc.)
- Linear by default — The main flow is sequential. Branching is only for special awards.
- Typed configs over JSON blobs — Each round type has explicit, documented fields.
- Explicit entities — Juries, submission windows, and confirmation steps are first-class models.
- Deep integration — Every feature connects. Jury groups link to rounds, rounds link to submissions, submissions link to evaluations.
- Admin override everywhere — Any automated decision can be manually overridden with audit trail.
Before & After: Architecture Comparison
BEFORE (Current System)
Program
└── Pipeline (generic container)
├── Track: "Main Competition" (MAIN)
│ ├── Stage: "Intake" (INTAKE, configJson: {...})
│ ├── Stage: "Filtering" (FILTER, configJson: {...})
│ ├── Stage: "Evaluation" (EVALUATION, configJson: {...})
│ ├── Stage: "Selection" (SELECTION, configJson: {...})
│ ├── Stage: "Live Finals" (LIVE_FINAL, configJson: {...})
│ └── Stage: "Results" (RESULTS, configJson: {...})
├── Track: "Award 1" (AWARD)
│ ├── Stage: "Evaluation" (EVALUATION)
│ └── Stage: "Results" (RESULTS)
└── Track: "Award 2" (AWARD)
├── Stage: "Evaluation" (EVALUATION)
└── Stage: "Results" (RESULTS)
Juries: implicit (assignments per stage, no named entity)
Submissions: single round (one INTAKE stage)
Mentoring: basic (messages + notes, no workspace)
Winner confirmation: none
AFTER (Redesigned System)
Program
└── Competition (purpose-built, replaces Pipeline)
├── Rounds (linear sequence, replaces Track+Stage):
│ ├── Round 1: "Application Window" ─────── (INTAKE)
│ ├── Round 2: "AI Screening" ──────────── (FILTERING)
│ ├── Round 3: "Jury 1 - Semi-finalist" ── (EVALUATION) ── juryGroupId: jury-1
│ ├── Round 4: "Semi-finalist Docs" ─────── (SUBMISSION) ── submissionWindowId: sw-2
│ ├── Round 5: "Jury 2 - Finalist" ──────── (EVALUATION) ── juryGroupId: jury-2
│ ├── Round 6: "Finalist Mentoring" ─────── (MENTORING)
│ ├── Round 7: "Live Finals" ────────────── (LIVE_FINAL) ── juryGroupId: jury-3
│ └── Round 8: "Confirm Winners" ─────────── (CONFIRMATION)
│
├── Jury Groups (explicit, named):
│ ├── "Jury 1" ── members: [judge-a, judge-b, ...] ── linked to Round 3
│ ├── "Jury 2" ── members: [judge-c, judge-d, ...] ── linked to Round 5
│ └── "Jury 3" ── members: [judge-e, judge-f, ...] ── linked to Round 7
│
├── Submission Windows (multi-round):
│ ├── Window 1: "Round 1 Docs" ── requirements: [Exec Summary, Business Plan]
│ └── Window 2: "Round 2 Docs" ── requirements: [Updated Plan, Video Pitch]
│
└── Special Awards (standalone):
├── "Innovation Award" ── mode: STAY_IN_MAIN, juryGroup: jury-2-award
└── "Impact Award" ── mode: SEPARATE_POOL, juryGroup: dedicated-jury
Key Decisions
1. Eliminate the Track Layer
Decision: Remove the Track model entirely. The main competition is a linear sequence of Rounds. Special awards become standalone entities.
Rationale: The MOPC competition has one main flow (Intake -> Filtering -> Jury 1 -> Submission 2 -> Jury 2 -> Mentoring -> Finals -> Confirmation). The Track concept (MAIN/AWARD/SHOWCASE with RoutingMode and DecisionMode) was designed for branching flows that don't exist in this competition. Awards don't need their own track — they're parallel evaluation/voting processes that reference the same projects.
Impact:
Trackmodel deletedTrackKind,RoutingModeenums deletedProjectStageState.trackIdremoved (becomesProjectRoundStatewith justprojectId+roundId)- Award tracks replaced with enhanced
SpecialAwardmodel - ~200 lines of Track CRUD code eliminated
2. Rename Pipeline -> Competition, Stage -> Round
Decision: Use domain-specific names that map to the competition vocabulary.
Rationale: Admins think in terms of "Competition 2026" and "Round 3: Jury 1 Evaluation", not "Pipeline" and "Stage". The rename costs nothing but improves comprehension.
3. Expand RoundType Enum
Decision: Add SUBMISSION, MENTORING, and CONFIRMATION to the existing types.
Current: INTAKE | FILTER | EVALUATION | SELECTION | LIVE_FINAL | RESULTS
New: INTAKE | FILTERING | EVALUATION | SUBMISSION | MENTORING | LIVE_FINAL | CONFIRMATION
Changes:
FILTER->FILTERING(clearer naming)SELECTIONremoved (merged into EVALUATION's advancement config)RESULTSremoved (results are a view, not a round — handled by the CONFIRMATION round output)SUBMISSIONadded (new doc requirements for advancing teams)MENTORINGadded (mentor-team workspace activation)CONFIRMATIONadded (multi-party winner agreement)
4. Explicit JuryGroup Model
Decision: Juries are first-class entities with names, members, and per-juror configuration.
Before: Assignments were per-stage with no grouping concept. "Jury 1" only existed in the admin's head.
After: JuryGroup model with members, linked to specific evaluation/live-final rounds. A juror can belong to multiple groups.
5. Multi-Round Submissions via SubmissionWindow
Decision: A new SubmissionWindow model handles document requirements per round, with automatic locking of previous windows.
Before: One INTAKE stage with one set of FileRequirement records.
After: Each submission window has its own requirements. When a new window opens, previous ones lock for applicants. Jury rounds can see docs from specific windows.
6. Typed Configs Replace JSON Blobs
Decision: Replace generic configJson: Json? with round-type-specific config models or strongly-typed JSON with Zod validation.
Before: Stage.configJson could be anything — you'd have to read the code to know what fields exist for each StageType.
After: Each round type has a documented, validated config shape. The wizard presents only the fields relevant to each type.
Scope Summary
| Area | Action | Complexity |
|---|---|---|
| Schema | Major changes (new models, renamed models, deleted Track) | High |
| Stage engine | Rename to round engine, simplify (no Track references) | Medium |
| Assignment service | Enhance with jury groups, hard/soft caps, category ratios | Medium |
| Filtering service | Minimal changes (rename stageId -> roundId) | Low |
| Live control | Enhanced stage manager UI, same core logic | Medium |
| Mentor system | Major enhancement (workspace, files, comments, promotion) | High |
| Winner confirmation | New system (proposal, approvals, freezing) | High |
| Special awards | Enhanced (standalone, two modes, own jury groups) | Medium |
| Notification system | Enhanced (deadline countdowns, reminder triggers) | Medium |
| Admin UI | Full redesign (competition wizard, round management) | High |
| Jury UI | Enhanced (multi-jury dashboard, cross-round docs) | Medium |
| Applicant UI | Enhanced (multi-round submissions, mentoring workspace) | Medium |
| Mentor UI | New (dedicated mentor dashboard and workspace) | High |
| API routers | Major refactor (rename, new endpoints, removed endpoints) | High |
| Migration | Data migration from old schema to new | Medium |
Document Index
| # | Document | Purpose |
|---|---|---|
| 00 | This document | Executive summary and key decisions |
| 01 | Current System Audit | What exists today — models, services, routers, UI |
| 02 | Gap Analysis | Current vs required, feature-by-feature comparison |
| 03 | Data Model | Complete Prisma schema redesign with migration SQL |
| 04 | Round: Intake | Application window, forms, deadlines, drafts |
| 05 | Round: Filtering | AI screening, eligibility, admin overrides |
| 06 | Round: Evaluation | Multi-jury, caps, ratios, scoring, advancement |
| 07 | Round: Submission | Multi-round docs, locking, jury visibility |
| 08 | Round: Mentoring | Private workspace, file comments, promotion |
| 09 | Round: Live Finals | Stage manager, live voting, deliberation |
| 10 | Round: Confirmation | Jury signatures, admin override, result freezing |
| 11 | Special Awards | Two modes, award juries, integration |
| 12 | Jury Groups | Multi-jury architecture, members, overrides |
| 13 | Notifications & Deadlines | Countdowns, reminders, window management |
| 14 | AI Services | Filtering, assignment, summaries, eligibility |
| 15 | Admin UI Redesign | Dashboard, wizard, round management |
| 16 | Jury UI Redesign | Dashboard, evaluation, live voting |
| 17 | Applicant UI Redesign | Dashboard, multi-round uploads, mentoring |
| 18 | Mentor UI Redesign | Dashboard, workspace, file review |
| 19 | API Router Reference | tRPC changes — new, modified, removed |
| 20 | Service Layer Changes | Engine, assignment, new services |
| 21 | Migration Strategy | Schema migration, data migration, rollback |
| 22 | Integration Map | Cross-reference of all feature connections |
| 23 | Implementation Sequence | Phased order with dependencies |