Round system redesign: Phases 1-7 complete

Full pipeline/track/stage architecture replacing the legacy round system.

Schema: 11 new models (Pipeline, Track, Stage, StageTransition,
ProjectStageState, RoutingRule, Cohort, CohortProject, LiveProgressCursor,
OverrideAction, AudienceVoter) + 8 new enums.

Backend: 9 new routers (pipeline, stage, routing, stageFiltering,
stageAssignment, cohort, live, decision, award) + 6 new services
(stage-engine, routing-engine, stage-filtering, stage-assignment,
stage-notifications, live-control).

Frontend: Pipeline wizard (17 components), jury stage pages (7),
applicant pipeline pages (3), public stage pages (2), admin pipeline
pages (5), shared stage components (3), SSE route, live hook.

Phase 6 refit: 23 routers/services migrated from roundId to stageId,
all frontend components refitted. Deleted round.ts (985 lines),
roundTemplate.ts, round-helpers.ts, round-settings.ts, round-type-settings.tsx,
10 legacy admin pages, 7 legacy jury pages, 3 legacy dialogs.

Phase 7 validation: 36 tests (10 unit + 8 integration files) all passing,
TypeScript 0 errors, Next.js build succeeds, 13 integrity checks,
legacy symbol sweep clean, auto-seed on first Docker startup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-13 13:57:09 +01:00
parent 8a328357e3
commit 331b67dae0
256 changed files with 29117 additions and 21424 deletions

View File

@@ -0,0 +1,97 @@
# API Contracts
## Contract Conventions
- All mutations return typed `errorCode` and machine-readable `details` on failure.
- All state-changing operations emit deterministic audit events.
- All response shapes include stable identifiers for client cache invalidation.
## Router Families
### `pipeline`
- `pipeline.create`
- `pipeline.update`
- `pipeline.simulate`
- `pipeline.publish`
- `pipeline.getSummary`
### `stage`
- `stage.create`
- `stage.updateConfig`
- `stage.list`
- `stage.transition`
- `stage.openWindow`
- `stage.closeWindow`
### `routing`
- `routing.preview`
- `routing.execute`
- `routing.listRules`
- `routing.upsertRule`
- `routing.toggleRule`
### `filtering`
- `filtering.previewBatch`
- `filtering.runStageFiltering`
- `filtering.getManualQueue`
- `filtering.resolveManualDecision`
### `assignment`
- `assignment.previewStageProjects`
- `assignment.assignStageProjects`
- `assignment.getCoverageReport`
- `assignment.rebalance`
### `cohort`
- `cohort.create`
- `cohort.assignProjects`
- `cohort.openVoting`
- `cohort.closeVoting`
### `live`
- `live.start`
- `live.setActiveProject`
- `live.jump`
- `live.reorder`
- `live.pause`
- `live.resume`
### `decision`
- `decision.override`
- `decision.auditTimeline`
### `award`
- `award.createTrack`
- `award.configureGovernance`
- `award.routeProjects`
- `award.finalizeWinners`
## Error Contract
- `BAD_REQUEST`
- `UNAUTHORIZED`
- `FORBIDDEN`
- `NOT_FOUND`
- `CONFLICT`
- `PRECONDITION_FAILED`
- `INTERNAL_SERVER_ERROR`
## Event Contract (Representative)
- `stage.transitioned`
- `routing.executed`
- `filtering.completed`
- `assignment.generated`
- `live.cursor.updated`
- `cohort.window.changed`
- `decision.overridden`
- `award.winner.finalized`

View File

@@ -0,0 +1,32 @@
# Authorization Matrix
Roles:
- `SUPER_ADMIN`
- `PROGRAM_ADMIN`
- `AWARD_MASTER`
- `JURY_MEMBER`
- `APPLICANT`
- `OBSERVER`
- `AUDIENCE` (public voting context)
| Capability | Super Admin | Program Admin | Award Master | Jury | Applicant | Observer | Audience |
|---|---|---|---|---|---|---|---|
| Create/Edit Pipeline | Yes | Yes (scoped) | No | No | No | No | No |
| Publish Pipeline | Yes | Yes (scoped) | No | No | No | No | No |
| Configure Stage Rules | Yes | Yes (scoped) | No | No | No | No | No |
| Execute Manual Transition | Yes | Yes (scoped) | Limited (award scoped) | No | No | No | No |
| Override Decision | Yes | Yes (scoped) | Limited (award scoped) | No | No | No | No |
| View Audit Timeline | Yes | Yes (scoped) | Award scoped | Own actions | No | Read-only scoped | No |
| Assign Jurors | Yes | Yes (scoped) | Award scoped | No | No | No | No |
| Submit Evaluation | No | No | Optional (if configured) | Yes (assigned only) | No | No | No |
| Upload Intake Docs | No | No | No | No | Yes | No | No |
| Control Live Cursor | Yes | Yes (scoped) | No | No | No | No | No |
| Cast Audience Vote | No | No | No | No | Optional | No | Yes |
## Policy Notes
1. Program scoping applies to all admin operations.
2. `AWARD_MASTER` permissions are explicitly award-scoped and only active when governance mode allows it.
3. Jury endpoints always enforce assignment ownership and window constraints.
4. Audience endpoints enforce cohort membership + window state + dedupe key policy.

View File

@@ -0,0 +1,16 @@
# Decision Log (Locked)
| ID | Decision | Status | Rationale | Impacted Phases |
|---|---|---|---|---|
| MX-001 | Canonical model is `Pipeline -> Track -> Stage` | Locked | Supports multi-track orchestration cleanly | 01-07 |
| MX-002 | Project progression stored in `ProjectStageState` records | Locked | Replaces brittle single-pointer round state | 01-07 |
| MX-003 | Intake is stage-native (`INTAKE`) rather than implicit pre-round behavior | Locked | Removes hidden workflow behavior | 01-04 |
| MX-004 | Full-cutover delivery with no compatibility bridge | Locked | Faster convergence to clean runtime | 00-07 |
| MX-005 | Special awards are first-class `Track` entities | Locked | Prevents duplicated orchestration logic | 01-06 |
| MX-006 | Award routing modes are `parallel`, `exclusive`, `post_main` | Locked | Supports real sponsor policy diversity | 02,05 |
| MX-007 | Award governance modes include `JURY_VOTE`, `AWARD_MASTER`, `ADMIN` | Locked | Explicit and policy-aligned control surfaces | 05 |
| MX-008 | Live progression source of truth is admin cursor | Locked | Needed for non-linear live event control | 02,04 |
| MX-009 | Voting windows are explicit open/close operations | Locked | Schedules alone are insufficient during live operations | 02,04 |
| MX-010 | Assignment engine guarantees eligible project coverage | Locked | Operational fairness and delivery reliability | 02,04 |
| MX-011 | Overrides require reason and immutable audit entries | Locked | Governance and explainability | 02,05,07 |
| MX-012 | Release is blocked by legacy symbol sweep failures | Locked | Prevents half-migrated runtime behavior | 06,07 |

View File

@@ -0,0 +1,75 @@
# Dependency Refit Inventory
This inventory is release-blocking. Every listed module must be validated against the new contracts.
## Backend Routers
- `src/server/routers/_app.ts`
- `src/server/routers/round.ts`
- `src/server/routers/filtering.ts`
- `src/server/routers/live-voting.ts`
- `src/server/routers/specialAward.ts`
- `src/server/routers/assignment.ts`
- `src/server/routers/evaluation.ts`
- `src/server/routers/file.ts`
- `src/server/routers/project.ts`
- `src/server/routers/project-pool.ts`
- `src/server/routers/application.ts`
- `src/server/routers/applicant.ts`
- `src/server/routers/export.ts`
- `src/server/routers/analytics.ts`
- `src/server/routers/program.ts`
- `src/server/routers/roundTemplate.ts`
- `src/server/routers/gracePeriod.ts`
- `src/server/routers/webhook.ts`
## Backend Services
- `src/server/services/smart-assignment.ts`
- `src/server/services/ai-filtering.ts`
- `src/server/services/ai-evaluation-summary.ts`
- `src/server/services/evaluation-reminders.ts`
- `src/server/services/in-app-notification.ts`
- `src/server/services/award-eligibility-job.ts`
- `src/server/services/webhook-dispatcher.ts`
## Admin Surfaces
- `src/app/(admin)/admin/rounds/**`
- `src/app/(admin)/admin/awards/**`
- `src/app/(admin)/admin/reports/page.tsx`
- `src/components/admin/round-pipeline.tsx`
- `src/components/admin/assign-projects-dialog.tsx`
- `src/components/admin/advance-projects-dialog.tsx`
- `src/components/admin/remove-projects-dialog.tsx`
- `src/components/admin/file-requirements-editor.tsx`
- `src/components/forms/round-type-settings.tsx`
## Jury, Applicant, Public
- `src/app/(jury)/jury/**`
- `src/components/jury/**`
- `src/app/(applicant)/applicant/**`
- `src/app/(public)/apply/**`
- `src/app/(public)/my-submission/**`
- `src/app/(public)/vote/**`
- `src/app/(public)/live-scores/**`
## Reporting and Exports
- chart and observer modules under `src/components/charts/**` and `src/components/observer/**`
- export and PDF paths under `src/components/shared/export-pdf-button.tsx`, `src/components/admin/pdf-report.tsx`, `src/server/routers/export.ts`
## Schema and Seed Paths
- `prisma/schema.prisma`
- relevant migrations and seed scripts under `prisma/`
## Mandatory Legacy Sweep Queries (Release Blockers)
1. `rg "trpc\.round" src`
2. `rg "\broundId\b" src/server src/components src/app`
3. `rg "round\.settingsJson|roundType" src/server src/components src/app`
4. `rg "model Round|enum RoundType" prisma/schema.prisma`
Allowlist exceptions (if any) must be explicit and approved in Phase 06 gates.

View File

@@ -0,0 +1,156 @@
# Domain Model and Contracts
## Canonical Enums
- `StageType = INTAKE | FILTER | EVALUATION | SELECTION | LIVE_FINAL | RESULTS`
- `TrackKind = MAIN | AWARD | SHOWCASE`
- `RoutingMode = PARALLEL | EXCLUSIVE | POST_MAIN`
- `StageStatus = DRAFT | ACTIVE | CLOSED | ARCHIVED`
- `ProjectStageStateValue = PENDING | IN_PROGRESS | PASSED | REJECTED | ROUTED | COMPLETED | WITHDRAWN`
- `DecisionMode = JURY_VOTE | AWARD_MASTER | ADMIN`
- `OverrideReasonCode = DATA_CORRECTION | POLICY_EXCEPTION | JURY_CONFLICT | SPONSOR_DECISION | ADMIN_DISCRETION`
## Core Entities
### Pipeline
- `id`
- `programId`
- `name`
- `slug`
- `status`
- `settingsJson`
- `createdAt`, `updatedAt`
### Track
- `id`
- `pipelineId`
- `kind`
- `specialAwardId?`
- `name`
- `slug`
- `sortOrder`
- `routingModeDefault?`
- `decisionMode?`
### Stage
- `id`
- `trackId`
- `stageType`
- `name`
- `slug`
- `sortOrder`
- `status`
- `configVersion`
- `configJson`
- `windowOpenAt?`, `windowCloseAt?`
### StageTransition
- `id`
- `fromStageId`
- `toStageId`
- `priority`
- `isDefault`
- `guardJson`
- `actionJson`
### ProjectStageState
- `id`
- `projectId`
- `trackId`
- `stageId`
- `state`
- `enteredAt`, `exitedAt`
- `decisionRef?`
- `outcomeJson`
### RoutingRule
- `id`
- `pipelineId`
- `scope` (`GLOBAL|TRACK|STAGE`)
- `predicateJson`
- `destinationTrackId`
- `destinationStageId?`
- `priority`
- `isActive`
### Cohort and Live Runtime
- `Cohort(id, stageId, name, votingMode, isOpen, windowOpenAt?, windowCloseAt?)`
- `CohortProject(cohortId, projectId, sortOrder)`
- `LiveProgressCursor(id, stageId, sessionId, activeProjectId?, activeOrderIndex?, updatedBy, updatedAt)`
### Governance Entities
- `OverrideAction(id, entityType, entityId, oldValueJson, newValueJson, reasonCode, reasonText, actedBy, actedAt)`
- `DecisionAuditLog(id, entityType, entityId, eventType, payloadJson, actorId?, createdAt)`
## Stage Config Union Contracts
### IntakeConfig
- file requirements
- accepted MIME and size constraints
- deadline and late policy
- team invite policy
### FilterConfig
- deterministic gates
- AI rubric
- confidence thresholds
- manual queue policy
- rejection notification policy
### EvaluationConfig
- criteria schema
- assignment strategy
- review thresholds
- COI policy
- visibility rules
### SelectionConfig
- ranking source
- finalist target
- override permissions
- promotion mode (`auto_top_n`, `hybrid`, `manual`)
### LiveFinalConfig
- session behavior
- jury voting config
- audience voting config
- cohort policy
- reveal policy
- schedule hints (advisory)
### ResultsConfig
- ranking weight rules
- publication policy
- winner override rules
## Constraint Rules
1. Stage ordering unique per track (`trackId + sortOrder`).
2. `ProjectStageState` unique on (`projectId`, `trackId`, `stageId`).
3. `StageTransition` unique on (`fromStageId`, `toStageId`).
4. Transition destination must remain in same pipeline unless explicit routing rule applies.
5. Override records immutable after insert.
6. Decision audit log append-only.
## Index Priorities
1. `ProjectStageState(projectId, trackId, state)`
2. `ProjectStageState(stageId, state)`
3. `RoutingRule(pipelineId, isActive, priority)`
4. `StageTransition(fromStageId, priority)`
5. `LiveProgressCursor(stageId, sessionId)`
6. `DecisionAuditLog(entityType, entityId, createdAt)`

View File

@@ -0,0 +1,32 @@
# Phase Gate Traceability
| Phase | Gate ID | Evidence Required | Test IDs / Checks | Blocking |
|---|---|---|---|---|
| 00 | G-00-1 | decision lock snapshot | decision-log review | Yes |
| 00 | G-00-2 | contract alignment review | API/type contract diff | Yes |
| 01 | G-01-1 | schema compile output | `prisma generate` | Yes |
| 01 | G-01-2 | reset/reseed output | seed logs + integrity queries | Yes |
| 01 | G-01-3 | index and FK evidence | SQL verification scripts | Yes |
| 02 | G-02-1 | transition runtime proof | U-001/U-002/I-001 | Yes |
| 02 | G-02-2 | routing determinism proof | U-003/I-003/I-004 | Yes |
| 02 | G-02-3 | filtering policy proof | U-004/U-005/E-003 | Yes |
| 02 | G-02-4 | assignment guarantees proof | U-006/U-007/I-005 | Yes |
| 02 | G-02-5 | audit/override proof | U-008/I-008 | Yes |
| 03 | G-03-1 | create/edit parity proof | parity checklist | Yes |
| 03 | G-03-2 | wizard completion proof | E-001 | Yes |
| 03 | G-03-3 | modal safety proof | targeted UI regressions | Yes |
| 04 | G-04-1 | applicant flow proof | E-002 | Yes |
| 04 | G-04-2 | jury flow proof | E-004 | Yes |
| 04 | G-04-3 | live audience proof | E-006/E-007/I-006/I-007 | Yes |
| 05 | G-05-1 | award routing proof | I-003/I-004 | Yes |
| 05 | G-05-2 | governance auth proof | U-010 + auth tests | Yes |
| 05 | G-05-3 | winner and audit proof | E-008 + I-008 | Yes |
| 06 | G-06-1 | dependency checklist complete | module sign-off evidence | Yes |
| 06 | G-06-2 | legacy sweeps clean | mandatory rg sweeps | Yes |
| 06 | G-06-3 | external consumer validation | webhook/export checks | Yes |
| 07 | G-07-1 | full test report | full matrix results | Yes |
| 07 | G-07-2 | performance report | P-001..P-004 evidence | Yes |
| 07 | G-07-3 | release evidence package | signed report template | Yes |
| 07 | G-07-4 | atomic cutover proof | release runbook logs | Yes |
Rule: no phase closes until all gates are complete with linked artifacts.

View File

@@ -0,0 +1,43 @@
# Program Charter
## Mission
Deliver a complete, stage-native orchestration platform for MOPC that supports:
- edition-scoped intake and progression
- deterministic filtering and assignment
- parallel and exclusive award flows
- admin-driven live finals operations
- full auditability and release-grade validation
## Scope
### In Scope
- Canonical data model rebuild around pipeline/track/stage.
- Backend orchestration engine (transition, routing, filtering, assignment, live, notifications, audit).
- Admin setup and control-plane UX refit.
- Applicant, jury, observer, and audience flow refit to new contracts.
- Special award governance modes including `AWARD_MASTER`.
- Platform-wide dependency refit of schema/runtime consumers.
- Full validation and atomic release process.
### Out of Scope
- Legacy contract compatibility bridges.
- Cosmetic redesign or major brand refresh.
- Non-orchestration feature expansion unrelated to competition lifecycle.
## Success Criteria
1. Admin setup can fully configure required competition behavior in create-time flow.
2. Stage progression and routing are deterministic and explainable.
3. Award tracks run without ad hoc side logic.
4. Live event operations are resilient under reconnect and burst traffic.
5. All platform dependencies are migrated and verified before release.
## Quality Bar
- Typed contracts at schema, API, and UI boundaries.
- Idempotent mutation semantics for high-risk operations.
- Strong audit trails for every governance-sensitive action.
- Mobile-safe interaction quality for live audience and jury experiences.

View File

@@ -0,0 +1,65 @@
# Release Evidence Report Template
## Build Metadata
- Date:
- Commit SHA:
- Environment:
- Operator:
## Phase Completion Summary
- Phase 00:
- Phase 01:
- Phase 02:
- Phase 03:
- Phase 04:
- Phase 05:
- Phase 06:
- Phase 07:
## Test Summary
- Unit: pass/fail counts
- Integration: pass/fail counts
- E2E: pass/fail counts
- Performance: pass/fail counts
## Mandatory Scenario Results
| ID | Result | Evidence Link | Notes |
|---|---|---|---|
| E-001 | | | |
| E-002 | | | |
| E-003 | | | |
| E-004 | | | |
| E-005 | | | |
| E-006 | | | |
| E-007 | | | |
| E-008 | | | |
## Performance Results
| ID | Result | Evidence Link | Notes |
|---|---|---|---|
| P-001 | | | |
| P-002 | | | |
| P-003 | | | |
| P-004 | | | |
## Legacy Sweep Results
- `trpc.round` references:
- `roundId` orchestration references:
- `round.settingsJson` behavior references:
- schema `Round` references:
## Known Issues
- None / list with severity and owner
## Sign-Off
- Engineering:
- Product:
- Operations:

View File

@@ -0,0 +1,17 @@
# Risk Register
| ID | Risk | Probability | Impact | Mitigation | Owner | Status |
|---|---|---|---|---|---|---|
| R-001 | Hidden legacy coupling after schema rebuild | Medium | High | Mandatory symbol sweeps + module refit gates | Eng Lead | Open |
| R-002 | Assignment coverage edge-case failures at scale | Medium | High | Hard overflow policy + P-001 load tests | Backend Lead | Open |
| R-003 | Award governance permission drift | Low | High | explicit authz tests for each decision mode | Security Lead | Open |
| R-004 | Live cursor race conditions during events | Medium | High | optimistic lock + replay-safe event handling | Realtime Lead | Open |
| R-005 | Audience vote dedupe regressions | Medium | Medium | dedupe key contract + E-007 + I-007 tests | Backend Lead | Open |
| R-006 | Migration/reseed script incompleteness | Low | High | repeatable reset/reseed rehearsals | DB Owner | Open |
| R-007 | Reporting consumers break on contract shift | Medium | Medium | phase-06 consumer validation checklist | Data Lead | Open |
| R-008 | Scope creep during dependency refit | High | Medium | strict out-of-scope policy, defer noncritical features | PM | Open |
## Risk Handling Policy
- `High impact` items require explicit mitigation evidence before phase close.
- `Open` high/high risks block release in Phase 07.

View File

@@ -0,0 +1,57 @@
# Test Matrix
All IDs are mandatory unless explicitly marked non-blocking with sign-off.
## Unit Tests
| ID | Area | Scenario | Expected |
|---|---|---|---|
| U-001 | Transition Engine | legal transition | persisted with audit event |
| U-002 | Transition Engine | illegal transition | typed validation error |
| U-003 | Routing | multiple rule match | deterministic priority winner |
| U-004 | Filtering Gates | missing required docs | blocked before AI pass |
| U-005 | AI Banding | uncertain confidence band | routed to manual queue |
| U-006 | Assignment | COI conflict | excluded from pool |
| U-007 | Assignment | insufficient capacity | overflow flagged + coverage preserved |
| U-008 | Override | missing reason fields | mutation rejected |
| U-009 | Live Cursor | concurrent cursor update | conflict handled and retried |
| U-010 | Award Governance | `AWARD_MASTER` on unauthorized award | forbidden |
## Integration Tests
| ID | Area | Scenario | Expected |
|---|---|---|---|
| I-001 | Pipeline CRUD | create/update/publish | graph integrity maintained |
| I-002 | Stage Config | invalid config schema | rejected |
| I-003 | Transition + Routing | filter pass to main + award parallel | dual states created |
| I-004 | Award Exclusive Routing | exclusive route | removed from main continuation |
| I-005 | Assignment API | preview vs execute parity | same constraints and outcomes |
| I-006 | Live Runtime | jump + reorder + open/close windows | consistent cursor state |
| I-007 | Cohort Voting | closed window submit | vote rejected |
| I-008 | Decision Audit | override applied | complete immutable timeline |
## End-to-End Tests
| ID | Persona | Scenario | Expected |
|---|---|---|---|
| E-001 | Admin | complete setup via wizard | no hidden edit-only blockers |
| E-002 | Applicant | upload intake requirements | status and deadlines enforced |
| E-003 | Admin | run filtering stage | gates + AI + manual queue behave |
| E-004 | Jury | complete evaluation workflow | criteria and lock policy enforced |
| E-005 | Admin | selection + override | finalists and audit aligned |
| E-006 | Live Admin | advance/back/jump + reorder | jury and audience sync realtime |
| E-007 | Audience | vote by cohort on mobile | visibility and dedupe enforced |
| E-008 | Admin | finalize results | ranking and publish outputs valid |
## Performance and Resilience
| ID | Area | Scenario | Threshold |
|---|---|---|---|
| P-001 | Assignment | 1000+ project batch | under agreed SLA |
| P-002 | Filtering | large AI queue | deterministic retry, no dropped jobs |
| P-003 | Live Voting | peak audience burst | acceptable p95 and no data loss |
| P-004 | Reconnect | disconnect/reconnect | state converges quickly |
## Release Block Rule
Any failing `U-*`, `I-*`, `E-*`, or `P-*` is release-blocking unless signed waiver exists.