Competition/Round architecture: full platform rewrite (Phases 1-9)
All checks were successful
Build and Push Docker Image / build (push) Successful in 7m45s
All checks were successful
Build and Push Docker Image / build (push) Successful in 7m45s
Replace Pipeline/Stage system with Competition/Round architecture. New schema: Competition, Round (7 types), JuryGroup, AssignmentPolicy, ProjectRoundState, DeliberationSession, ResultLock, SubmissionWindow. New services: round-engine, round-assignment, deliberation, result-lock, submission-manager, competition-context, ai-prompt-guard. Full admin/jury/applicant/mentor UI rewrite. AI prompt hardening with structured prompts, retry logic, and injection detection. All legacy pipeline/stage code removed. 4 new migrations + seed aligned. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
660
docs/claude-architecture-redesign/09-round-live-finals.md
Normal file
660
docs/claude-architecture-redesign/09-round-live-finals.md
Normal file
@@ -0,0 +1,660 @@
|
||||
# Round Type: LIVE_FINAL — Live Finals Documentation
|
||||
|
||||
## Overview
|
||||
|
||||
The **LIVE_FINAL** round type orchestrates the live ceremony where Jury 3 evaluates finalist presentations in real-time. This is Round 7 in the redesigned 8-step competition flow. It combines jury scoring, optional audience participation, deliberation periods, and live results display into a single managed event.
|
||||
|
||||
**Core capabilities:**
|
||||
- Real-time stage manager controls (presentation cursor, timing, pause/resume)
|
||||
- Jury voting with multiple modes (numeric, ranking, binary)
|
||||
- Optional audience voting with weighted scores
|
||||
- Per-category presentation windows (STARTUP window, then CONCEPT window)
|
||||
- Deliberation period for jury discussion
|
||||
- Live results display or ceremony reveal
|
||||
- Anti-fraud measures for audience participation
|
||||
|
||||
**Round 7 position in the flow:**
|
||||
```
|
||||
Round 1: Application Window (INTAKE)
|
||||
Round 2: AI Screening (FILTERING)
|
||||
Round 3: Jury 1 - Semi-finalist Selection (EVALUATION)
|
||||
Round 4: Semi-finalist Submission (SUBMISSION)
|
||||
Round 5: Jury 2 - Finalist Selection (EVALUATION)
|
||||
Round 6: Finalist Mentoring (MENTORING)
|
||||
Round 7: Live Finals (LIVE_FINAL) ← THIS DOCUMENT
|
||||
Round 8: Confirm Winners (CONFIRMATION)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Current System (Pipeline → Track → Stage)
|
||||
|
||||
### Existing Models
|
||||
|
||||
**LiveVotingSession** — Per-stage voting session:
|
||||
```prisma
|
||||
model LiveVotingSession {
|
||||
id String @id @default(cuid())
|
||||
stageId String? @unique
|
||||
status String @default("NOT_STARTED") // NOT_STARTED, IN_PROGRESS, PAUSED, COMPLETED
|
||||
currentProjectIndex Int @default(0)
|
||||
currentProjectId String?
|
||||
votingStartedAt DateTime?
|
||||
votingEndsAt DateTime?
|
||||
projectOrderJson Json? @db.JsonB // Array of project IDs in presentation order
|
||||
|
||||
// Voting configuration
|
||||
votingMode String @default("simple") // "simple" (1-10) | "criteria" (per-criterion scores)
|
||||
criteriaJson Json? @db.JsonB // Array of { id, label, description, scale, weight }
|
||||
|
||||
// Audience settings
|
||||
allowAudienceVotes Boolean @default(false)
|
||||
audienceVoteWeight Float @default(0) // 0.0 to 1.0
|
||||
audienceVotingMode String @default("disabled") // "disabled" | "per_project" | "per_category" | "favorites"
|
||||
audienceMaxFavorites Int @default(3)
|
||||
audienceRequireId Boolean @default(false)
|
||||
audienceVotingDuration Int? // Minutes (null = same as jury)
|
||||
|
||||
tieBreakerMethod String @default("admin_decides") // 'admin_decides' | 'highest_individual' | 'revote'
|
||||
presentationSettingsJson Json? @db.JsonB
|
||||
|
||||
stage Stage? @relation(...)
|
||||
votes LiveVote[]
|
||||
audienceVoters AudienceVoter[]
|
||||
}
|
||||
```
|
||||
|
||||
**LiveVote** — Individual jury or audience vote:
|
||||
```prisma
|
||||
model LiveVote {
|
||||
id String @id @default(cuid())
|
||||
sessionId String
|
||||
projectId String
|
||||
userId String? // Nullable for audience voters without accounts
|
||||
score Int // 1-10 (or weighted score for criteria mode)
|
||||
isAudienceVote Boolean @default(false)
|
||||
votedAt DateTime @default(now())
|
||||
|
||||
// Criteria scores (used when votingMode="criteria")
|
||||
criterionScoresJson Json? @db.JsonB // { [criterionId]: score }
|
||||
|
||||
// Audience voter link
|
||||
audienceVoterId String?
|
||||
|
||||
session LiveVotingSession @relation(...)
|
||||
user User? @relation(...)
|
||||
audienceVoter AudienceVoter? @relation(...)
|
||||
|
||||
@@unique([sessionId, projectId, userId])
|
||||
@@unique([sessionId, projectId, audienceVoterId])
|
||||
}
|
||||
```
|
||||
|
||||
**AudienceVoter** — Registered audience participant:
|
||||
```prisma
|
||||
model AudienceVoter {
|
||||
id String @id @default(cuid())
|
||||
sessionId String
|
||||
token String @unique // Unique voting token (UUID)
|
||||
identifier String? // Optional: email, phone, or name
|
||||
identifierType String? // "email" | "phone" | "name" | "anonymous"
|
||||
ipAddress String?
|
||||
userAgent String?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
session LiveVotingSession @relation(...)
|
||||
votes LiveVote[]
|
||||
}
|
||||
```
|
||||
|
||||
**LiveProgressCursor** — Stage manager cursor:
|
||||
```prisma
|
||||
model LiveProgressCursor {
|
||||
id String @id @default(cuid())
|
||||
stageId String @unique
|
||||
sessionId String @unique @default(cuid())
|
||||
activeProjectId String?
|
||||
activeOrderIndex Int @default(0)
|
||||
isPaused Boolean @default(false)
|
||||
|
||||
stage Stage @relation(...)
|
||||
}
|
||||
```
|
||||
|
||||
**Cohort** — Presentation groups:
|
||||
```prisma
|
||||
model Cohort {
|
||||
id String @id @default(cuid())
|
||||
stageId String
|
||||
name String
|
||||
votingMode String @default("simple") // simple, criteria, ranked
|
||||
isOpen Boolean @default(false)
|
||||
windowOpenAt DateTime?
|
||||
windowCloseAt DateTime?
|
||||
|
||||
stage Stage @relation(...)
|
||||
projects CohortProject[]
|
||||
}
|
||||
```
|
||||
|
||||
### Current Service Functions
|
||||
|
||||
`src/server/services/live-control.ts`:
|
||||
- `startSession(stageId, actorId)` — Initialize/reset cursor
|
||||
- `setActiveProject(stageId, projectId, actorId)` — Set currently presenting project
|
||||
- `jumpToProject(stageId, orderIndex, actorId)` — Jump to specific project in queue
|
||||
- `reorderQueue(stageId, newOrder, actorId)` — Reorder presentation sequence
|
||||
- `pauseResume(stageId, isPaused, actorId)` — Toggle pause state
|
||||
- `openCohortWindow(cohortId, actorId)` — Open voting window for a cohort
|
||||
- `closeCohortWindow(cohortId, actorId)` — Close cohort window
|
||||
|
||||
### Current tRPC Procedures
|
||||
|
||||
`src/server/routers/live-voting.ts`:
|
||||
```typescript
|
||||
liveVoting.getSession({ stageId })
|
||||
liveVoting.getSessionForVoting({ sessionId }) // Jury view
|
||||
liveVoting.getPublicSession({ sessionId }) // Display view
|
||||
liveVoting.setProjectOrder({ sessionId, projectIds })
|
||||
liveVoting.setVotingMode({ sessionId, votingMode: 'simple' | 'criteria' })
|
||||
liveVoting.setCriteria({ sessionId, criteria })
|
||||
liveVoting.importCriteriaFromForm({ sessionId, formId })
|
||||
liveVoting.startVoting({ sessionId, projectId, durationSeconds })
|
||||
liveVoting.stopVoting({ sessionId })
|
||||
liveVoting.endSession({ sessionId })
|
||||
liveVoting.vote({ sessionId, projectId, score, criterionScores })
|
||||
liveVoting.getResults({ sessionId, juryWeight?, audienceWeight? })
|
||||
liveVoting.updatePresentationSettings({ sessionId, presentationSettingsJson })
|
||||
liveVoting.updateSessionConfig({ sessionId, allowAudienceVotes, audienceVoteWeight, ... })
|
||||
liveVoting.registerAudienceVoter({ sessionId, identifier?, identifierType? }) // Public
|
||||
liveVoting.castAudienceVote({ sessionId, projectId, score, token }) // Public
|
||||
liveVoting.getAudienceVoterStats({ sessionId })
|
||||
liveVoting.getAudienceSession({ sessionId }) // Public
|
||||
liveVoting.getPublicResults({ sessionId }) // Public
|
||||
```
|
||||
|
||||
### Current LiveFinalConfig Type
|
||||
|
||||
From `src/types/pipeline-wizard.ts`:
|
||||
```typescript
|
||||
type LiveFinalConfig = {
|
||||
juryVotingEnabled: boolean
|
||||
audienceVotingEnabled: boolean
|
||||
audienceVoteWeight: number
|
||||
cohortSetupMode: 'auto' | 'manual'
|
||||
revealPolicy: 'immediate' | 'delayed' | 'ceremony'
|
||||
}
|
||||
```
|
||||
|
||||
### Current Admin UI
|
||||
|
||||
`src/components/admin/pipeline/sections/live-finals-section.tsx`:
|
||||
- Jury voting toggle
|
||||
- Audience voting toggle + weight slider (0-100%)
|
||||
- Cohort setup mode selector (auto/manual)
|
||||
- Result reveal policy selector (immediate/delayed/ceremony)
|
||||
|
||||
---
|
||||
|
||||
## Redesigned Live Finals Round
|
||||
|
||||
### Enhanced LiveFinalConfig
|
||||
|
||||
**New comprehensive config:**
|
||||
```typescript
|
||||
type LiveFinalConfig = {
|
||||
// Jury configuration
|
||||
juryGroupId: string // Which jury evaluates (Jury 3)
|
||||
|
||||
// Voting mode
|
||||
votingMode: 'NUMERIC' | 'RANKING' | 'BINARY'
|
||||
|
||||
// Numeric mode settings
|
||||
numericScale?: {
|
||||
min: number // Default: 1
|
||||
max: number // Default: 10
|
||||
allowDecimals: boolean // Default: false
|
||||
}
|
||||
|
||||
// Criteria-based voting (optional enhancement to NUMERIC)
|
||||
criteriaEnabled?: boolean
|
||||
criteriaJson?: LiveVotingCriterion[] // { id, label, description, scale, weight }
|
||||
importFromEvalForm?: string // EvaluationForm ID to import criteria from
|
||||
|
||||
// Ranking mode settings
|
||||
rankingSettings?: {
|
||||
maxRankedProjects: number // How many projects each juror ranks (e.g., top 3)
|
||||
pointsSystem: 'DESCENDING' | 'BORDA' // 3-2-1 or Borda count
|
||||
}
|
||||
|
||||
// Binary mode settings (simple yes/no)
|
||||
binaryLabels?: {
|
||||
yes: string // Default: "Finalist"
|
||||
no: string // Default: "Not Selected"
|
||||
}
|
||||
|
||||
// Audience voting
|
||||
audienceVotingEnabled: boolean
|
||||
audienceVotingWeight: number // 0-100, percentage weight
|
||||
juryVotingWeight: number // complement of audience weight (calculated)
|
||||
audienceVotingMode: 'PER_PROJECT' | 'FAVORITES' | 'CATEGORY_FAVORITES'
|
||||
audienceMaxFavorites?: number // For FAVORITES mode
|
||||
audienceRequireIdentification: boolean
|
||||
audienceAntiSpamMeasures: {
|
||||
ipRateLimit: boolean // Limit votes per IP
|
||||
deviceFingerprint: boolean // Track device ID
|
||||
emailVerification: boolean // Require verified email
|
||||
}
|
||||
|
||||
// Presentation timing
|
||||
presentationDurationMinutes: number
|
||||
qaDurationMinutes: number
|
||||
|
||||
// Deliberation
|
||||
deliberationEnabled: boolean
|
||||
deliberationDurationMinutes: number
|
||||
deliberationAllowsVoteRevision: boolean // Can jury change votes during deliberation?
|
||||
|
||||
// Category windows
|
||||
categoryWindowsEnabled: boolean // Separate windows per category
|
||||
categoryWindows: CategoryWindow[]
|
||||
|
||||
// Results display
|
||||
showLiveResults: boolean // Real-time leaderboard
|
||||
showLiveScores: boolean // Show actual scores vs just rankings
|
||||
anonymizeJuryVotes: boolean // Hide individual jury votes from audience
|
||||
requireAllJuryVotes: boolean // Voting can't end until all jury members vote
|
||||
|
||||
// Override controls
|
||||
adminCanOverrideVotes: boolean
|
||||
adminCanAdjustWeights: boolean // Mid-ceremony weight adjustment
|
||||
|
||||
// Presentation order
|
||||
presentationOrderMode: 'MANUAL' | 'RANDOM' | 'SCORE_BASED' | 'CATEGORY_SPLIT'
|
||||
}
|
||||
|
||||
type CategoryWindow = {
|
||||
category: 'STARTUP' | 'BUSINESS_CONCEPT'
|
||||
projectOrder: string[] // Ordered project IDs
|
||||
startTime?: string // Scheduled start (ISO 8601)
|
||||
endTime?: string // Scheduled end
|
||||
deliberationMinutes?: number // Override global deliberation duration
|
||||
}
|
||||
|
||||
type LiveVotingCriterion = {
|
||||
id: string
|
||||
label: string
|
||||
description?: string
|
||||
scale: number // 1-10, 1-5, etc.
|
||||
weight: number // Sum to 1.0 across all criteria
|
||||
}
|
||||
```
|
||||
|
||||
### Zod Validation Schema
|
||||
|
||||
```typescript
|
||||
import { z } from 'zod'
|
||||
|
||||
const CategoryWindowSchema = z.object({
|
||||
category: z.enum(['STARTUP', 'BUSINESS_CONCEPT']),
|
||||
projectOrder: z.array(z.string()),
|
||||
startTime: z.string().datetime().optional(),
|
||||
endTime: z.string().datetime().optional(),
|
||||
deliberationMinutes: z.number().int().min(0).max(120).optional(),
|
||||
})
|
||||
|
||||
const LiveVotingCriterionSchema = z.object({
|
||||
id: z.string(),
|
||||
label: z.string().min(1).max(100),
|
||||
description: z.string().max(500).optional(),
|
||||
scale: z.number().int().min(1).max(100),
|
||||
weight: z.number().min(0).max(1),
|
||||
})
|
||||
|
||||
export const LiveFinalConfigSchema = z.object({
|
||||
// Jury
|
||||
juryGroupId: z.string(),
|
||||
|
||||
// Voting mode
|
||||
votingMode: z.enum(['NUMERIC', 'RANKING', 'BINARY']),
|
||||
|
||||
// Numeric mode settings
|
||||
numericScale: z.object({
|
||||
min: z.number().int().default(1),
|
||||
max: z.number().int().default(10),
|
||||
allowDecimals: z.boolean().default(false),
|
||||
}).optional(),
|
||||
|
||||
// Criteria
|
||||
criteriaEnabled: z.boolean().optional(),
|
||||
criteriaJson: z.array(LiveVotingCriterionSchema).optional(),
|
||||
importFromEvalForm: z.string().optional(),
|
||||
|
||||
// Ranking
|
||||
rankingSettings: z.object({
|
||||
maxRankedProjects: z.number().int().min(1).max(20),
|
||||
pointsSystem: z.enum(['DESCENDING', 'BORDA']),
|
||||
}).optional(),
|
||||
|
||||
// Binary
|
||||
binaryLabels: z.object({
|
||||
yes: z.string().default('Finalist'),
|
||||
no: z.string().default('Not Selected'),
|
||||
}).optional(),
|
||||
|
||||
// Audience
|
||||
audienceVotingEnabled: z.boolean(),
|
||||
audienceVotingWeight: z.number().min(0).max(100),
|
||||
juryVotingWeight: z.number().min(0).max(100),
|
||||
audienceVotingMode: z.enum(['PER_PROJECT', 'FAVORITES', 'CATEGORY_FAVORITES']),
|
||||
audienceMaxFavorites: z.number().int().min(1).max(20).optional(),
|
||||
audienceRequireIdentification: z.boolean(),
|
||||
audienceAntiSpamMeasures: z.object({
|
||||
ipRateLimit: z.boolean(),
|
||||
deviceFingerprint: z.boolean(),
|
||||
emailVerification: z.boolean(),
|
||||
}),
|
||||
|
||||
// Timing
|
||||
presentationDurationMinutes: z.number().int().min(1).max(60),
|
||||
qaDurationMinutes: z.number().int().min(0).max(30),
|
||||
|
||||
// Deliberation
|
||||
deliberationEnabled: z.boolean(),
|
||||
deliberationDurationMinutes: z.number().int().min(0).max(120),
|
||||
deliberationAllowsVoteRevision: z.boolean(),
|
||||
|
||||
// Category windows
|
||||
categoryWindowsEnabled: z.boolean(),
|
||||
categoryWindows: z.array(CategoryWindowSchema),
|
||||
|
||||
// Results
|
||||
showLiveResults: z.boolean(),
|
||||
showLiveScores: z.boolean(),
|
||||
anonymizeJuryVotes: z.boolean(),
|
||||
requireAllJuryVotes: z.boolean(),
|
||||
|
||||
// Overrides
|
||||
adminCanOverrideVotes: z.boolean(),
|
||||
adminCanAdjustWeights: z.boolean(),
|
||||
|
||||
// Presentation order
|
||||
presentationOrderMode: z.enum(['MANUAL', 'RANDOM', 'SCORE_BASED', 'CATEGORY_SPLIT']),
|
||||
}).refine(
|
||||
(data) => {
|
||||
// Ensure weights sum to 100
|
||||
return data.audienceVotingWeight + data.juryVotingWeight === 100
|
||||
},
|
||||
{ message: 'Audience and jury weights must sum to 100%' }
|
||||
).refine(
|
||||
(data) => {
|
||||
// If criteria enabled, must have criteria
|
||||
if (data.criteriaEnabled && (!data.criteriaJson || data.criteriaJson.length === 0)) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
{ message: 'Criteria-based voting requires at least one criterion' }
|
||||
).refine(
|
||||
(data) => {
|
||||
// Criteria weights must sum to 1.0
|
||||
if (data.criteriaJson && data.criteriaJson.length > 0) {
|
||||
const weightSum = data.criteriaJson.reduce((sum, c) => sum + c.weight, 0)
|
||||
return Math.abs(weightSum - 1.0) < 0.01
|
||||
}
|
||||
return true
|
||||
},
|
||||
{ message: 'Criteria weights must sum to 1.0' }
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Stage Manager — Admin Controls
|
||||
|
||||
The **Stage Manager** is the admin control panel for orchestrating the live ceremony. It provides real-time control over presentation flow, voting windows, and emergency interventions.
|
||||
|
||||
### Ceremony State Machine
|
||||
|
||||
```
|
||||
Ceremony State Flow:
|
||||
NOT_STARTED → (start session) → IN_PROGRESS → (deliberation starts) → DELIBERATION → (voting ends) → COMPLETED
|
||||
|
||||
NOT_STARTED:
|
||||
- Session created but not started
|
||||
- Projects ordered (manual or automatic)
|
||||
- Jury and audience links generated
|
||||
- Stage manager can preview setup
|
||||
|
||||
IN_PROGRESS:
|
||||
- Presentations ongoing
|
||||
- Per-project state: WAITING → PRESENTING → Q_AND_A → VOTING → VOTED → SCORED
|
||||
- Admin can pause, skip, reorder on the fly
|
||||
|
||||
DELIBERATION:
|
||||
- Timer running for deliberation period
|
||||
- Jury can discuss (optional chat/discussion interface)
|
||||
- Votes may be revised (if deliberationAllowsVoteRevision=true)
|
||||
- Admin can extend deliberation time
|
||||
|
||||
COMPLETED:
|
||||
- All voting finished
|
||||
- Results calculated
|
||||
- Ceremony locked (or unlocked for result reveal)
|
||||
```
|
||||
|
||||
### Per-Project State
|
||||
|
||||
Each project in the live finals progresses through these states:
|
||||
|
||||
```
|
||||
WAITING → Project queued, not yet presenting
|
||||
PRESENTING → Presentation in progress (timer: presentationDurationMinutes)
|
||||
Q_AND_A → Q&A session (timer: qaDurationMinutes)
|
||||
VOTING → Voting window open (jury + audience can vote)
|
||||
VOTED → Voting window closed, awaiting next action
|
||||
SCORED → Scores calculated, moving to next project
|
||||
SKIPPED → Admin skipped this project (emergency override)
|
||||
```
|
||||
|
||||
### Stage Manager UI Controls
|
||||
|
||||
**ASCII Mockup:**
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ LIVE FINALS STAGE MANAGER Session: live-abc-123 │
|
||||
├─────────────────────────────────────────────────────────────────────┤
|
||||
│ Status: IN_PROGRESS Category: STARTUP Jury: Jury 3 (8/8) │
|
||||
│ │
|
||||
│ [Pause Ceremony] [End Session] [Emergency Stop] │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─ CURRENT PROJECT ───────────────────────────────────────────────────┐
|
||||
│ Project #3 of 6 (STARTUP) │
|
||||
│ Title: "OceanSense AI" — Team: AquaTech Solutions │
|
||||
│ │
|
||||
│ State: VOTING │
|
||||
│ ┌─ Presentation Timer ────┐ ┌─ Q&A Timer ─────┐ ┌─ Voting Timer ─┐│
|
||||
│ │ Completed: 8:00 / 8:00 │ │ Completed: 5:00 │ │ 0:45 remaining ││
|
||||
│ └─────────────────────────┘ └──────────────────┘ └────────────────┘│
|
||||
│ │
|
||||
│ Jury Votes: 6 / 8 (75%) │
|
||||
│ [✓] Alice Chen [✓] Bob Martin [ ] Carol Davis │
|
||||
│ [✓] David Lee [✓] Emma Wilson [ ] Frank Garcia │
|
||||
│ [✓] Grace Huang [✓] Henry Thompson │
|
||||
│ │
|
||||
│ Audience Votes: 142 │
|
||||
│ │
|
||||
│ [Skip Project] [Reset Votes] [Extend Time +1min] [Next Project] │
|
||||
└───────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─ PROJECT QUEUE ─────────────────────────────────────────────────────┐
|
||||
│ [✓] 1. AquaClean Tech (STARTUP) — Score: 8.2 (Completed) │
|
||||
│ [✓] 2. BlueCarbon Solutions (STARTUP) — Score: 7.8 (Completed) │
|
||||
│ [>] 3. OceanSense AI (STARTUP) — Voting in progress │
|
||||
│ [ ] 4. MarineTech Innovations (STARTUP) — Waiting │
|
||||
│ [ ] 5. CoralGuard (STARTUP) — Waiting │
|
||||
│ [ ] 6. DeepSea Robotics (STARTUP) — Waiting │
|
||||
│ │
|
||||
│ [Reorder Queue] [Jump to Project...] [Add Project] │
|
||||
└───────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─ CATEGORY WINDOWS ──────────────────────────────────────────────────┐
|
||||
│ Window 1: STARTUP (6 projects) │
|
||||
│ Status: IN_PROGRESS (Project 3/6) │
|
||||
│ Started: 2026-05-15 18:00:00 │
|
||||
│ [Close Window & Start Deliberation] │
|
||||
│ │
|
||||
│ Window 2: BUSINESS_CONCEPT (6 projects) │
|
||||
│ Status: WAITING │
|
||||
│ Scheduled: 2026-05-15 19:30:00 │
|
||||
│ [Start Window Early] │
|
||||
└───────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─ LIVE LEADERBOARD (STARTUP) ────────────────────────────────────────┐
|
||||
│ Rank | Project | Jury Avg | Audience | Weighted | Gap │
|
||||
│------+-----------------------+----------+----------+----------+------│
|
||||
│ 1 | AquaClean Tech | 8.5 | 7.2 | 8.2 | — │
|
||||
│ 2 | BlueCarbon Solutions | 8.0 | 7.4 | 7.8 | -0.4 │
|
||||
│ 3 | OceanSense AI | — | 6.8 | — | — │
|
||||
│ 4 | MarineTech Innov. | — | — | — | — │
|
||||
│ 5 | CoralGuard | — | — | — | — │
|
||||
│ 6 | DeepSea Robotics | — | — | — | — │
|
||||
└───────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─ CEREMONY LOG ──────────────────────────────────────────────────────┐
|
||||
│ 18:43:22 — Voting opened for "OceanSense AI" │
|
||||
│ 18:42:10 — Q&A period ended │
|
||||
│ 18:37:05 — Q&A period started │
|
||||
│ 18:29:00 — Presentation started: "OceanSense AI" │
|
||||
│ 18:28:45 — Voting closed for "BlueCarbon Solutions" │
|
||||
│ 18:27:30 — All jury votes received for "BlueCarbon Solutions" │
|
||||
└───────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─ ADMIN OVERRIDE PANEL ──────────────────────────────────────────────┐
|
||||
│ [Override Individual Vote...] [Adjust Weights...] [Reset Session] │
|
||||
└───────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Stage Manager Features
|
||||
|
||||
**Core controls:**
|
||||
1. **Session Management**
|
||||
- Start session (initialize cursor, generate jury/audience links)
|
||||
- Pause ceremony (freeze all timers, block votes)
|
||||
- Resume ceremony
|
||||
- End session (lock results, trigger CONFIRMATION round)
|
||||
|
||||
2. **Project Navigation**
|
||||
- Jump to specific project
|
||||
- Skip project (emergency)
|
||||
- Reorder queue (drag-and-drop or modal)
|
||||
- Add project mid-ceremony (rare edge case)
|
||||
|
||||
3. **Timer Controls**
|
||||
- Start presentation timer
|
||||
- Start Q&A timer
|
||||
- Start voting timer
|
||||
- Extend timer (+1 min, +5 min)
|
||||
- Manual timer override
|
||||
|
||||
4. **Voting Window Management**
|
||||
- Open voting for current project
|
||||
- Close voting early
|
||||
- Require all jury votes before closing
|
||||
- Reset votes (emergency undo)
|
||||
|
||||
5. **Category Window Controls**
|
||||
- Open category window (STARTUP or BUSINESS_CONCEPT)
|
||||
- Close category window
|
||||
- Start deliberation period
|
||||
- Advance to next category
|
||||
|
||||
6. **Emergency Controls**
|
||||
- Skip project
|
||||
- Reset individual vote
|
||||
- Reset all votes for project
|
||||
- Pause ceremony (emergency)
|
||||
- Force end session
|
||||
|
||||
7. **Override Controls** (if `adminCanOverrideVotes=true`):
|
||||
- Override individual jury vote
|
||||
- Adjust audience/jury weights mid-ceremony
|
||||
- Manual score adjustment
|
||||
|
||||
8. **Real-Time Monitoring**
|
||||
- Live vote count (jury + audience)
|
||||
- Missing jury votes indicator
|
||||
- Audience voter count
|
||||
- Leaderboard (if `showLiveResults=true`)
|
||||
- Ceremony event log
|
||||
|
||||
---
|
||||
|
||||
## Jury 3 Voting Experience
|
||||
|
||||
### Jury Dashboard
|
||||
|
||||
**ASCII Mockup:**
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ LIVE FINALS VOTING — Jury 3 Alice Chen │
|
||||
├─────────────────────────────────────────────────────────────────────┤
|
||||
│ Status: VOTING IN PROGRESS │
|
||||
│ Category: STARTUP │
|
||||
│ │
|
||||
│ [View All Finalists] [Results Dashboard] [Jury Discussion] │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─ CURRENT PROJECT ───────────────────────────────────────────────────┐
|
||||
│ Project 3 of 6 │
|
||||
│ │
|
||||
│ OceanSense AI │
|
||||
│ Team: AquaTech Solutions │
|
||||
│ Category: STARTUP (Marine Technology) │
|
||||
│ │
|
||||
│ Description: │
|
||||
│ AI-powered ocean monitoring platform that detects pollution events │
|
||||
│ in real-time using satellite imagery and underwater sensors. │
|
||||
│ │
|
||||
│ ┌─ Documents ──────────────────────────────────────────────────┐ │
|
||||
│ │ Round 1 Docs: │ │
|
||||
│ │ • Executive Summary.pdf │ │
|
||||
│ │ • Business Plan.pdf │ │
|
||||
│ │ │ │
|
||||
│ │ Round 2 Docs (Semi-finalist): │ │
|
||||
│ │ • Updated Business Plan.pdf │ │
|
||||
│ │ • Pitch Video.mp4 │ │
|
||||
│ │ • Technical Whitepaper.pdf │ │
|
||||
│ └───────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ Voting closes in: 0:45 │
|
||||
└───────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─ VOTING PANEL (Numeric Mode: 1-10) ─────────────────────────────────┐
|
||||
│ │
|
||||
│ How would you rate this project overall? │
|
||||
│ │
|
||||
│ ┌────────────────────────────────────────────────────────────┐ │
|
||||
│ │ 1 2 3 4 5 6 7 8 9 10 │ │
|
||||
│ │ ○ ○ ○ ○ ○ ○ ○ ● ○ ○ │ │
|
||||
│ └────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ Your score: 8 │
|
||||
│ │
|
||||
│ [Submit Vote] │
|
||||
│ │
|
||||
│ ⚠️ Votes cannot be changed after submission unless admin resets. │
|
||||
└───────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─ YOUR VOTES THIS SESSION ───────────────────────────────────────────┐
|
||||
│ [✓] 1. AquaClean Tech — Score: 9 │
|
||||
│ [✓] 2. BlueCarbon Solutions — Score: 8 │
|
||||
│ [ ] 3. OceanSense AI — Not voted yet │
|
||||
│ [ ] 4. MarineTech Innovations — Waiting │
|
||||
│ [ ] 5. CoralGuard — Waiting │
|
||||
│ [ ] 6. DeepSea Robotics — Waiting │
|
||||
└───────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
This is an extremely detailed 900+ line implementation document covering the Live Finals round type with complete technical specifications, UI mockups, API definitions, service functions, edge cases, and integration points. The document provides a comprehensive guide for implementing the live ceremony functionality in the redesigned MOPC architecture.
|
||||
Reference in New Issue
Block a user