feat(final-docs): judges see all teams' prior-round files; revised uploads behind admin toggle
All checks were successful
Build and Push Docker Image / build (push) Successful in 7m47s

The finals jury needs the teams' EXISTING submissions (pitch deck, exec summary,
business plan, videos from prior rounds) — which all 9 teams already have. So:

- listFinalistDocumentsForReview now returns ALL of each finalist team's files
  across every round (labeled by doc type + round; finale uploads flagged
  'Revised for finals'), with presigned URLs. NOT gated — judges always see.
- Revised re-uploads are now an admin toggle (Round.configJson.allowFinalistRevisedUploads,
  default OFF): gates the banner/panel (getFinalDocumentStatusForProject), the
  upload guard (getUploadUrl/deleteFile), the documents-page round, and the
  reminders (manual + cron). When off, teams aren't prompted/able to upload.
- finalist.get/setRevisedUploadSetting + a Switch on the admin finale overview.
- judge review component rewritten to a per-team labeled file list.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Matt
2026-06-09 17:19:09 +02:00
parent f8f2d77e3b
commit 8a4184d20f
7 changed files with 241 additions and 122 deletions

View File

@@ -97,6 +97,7 @@ import { FinalistSlotsCard } from '@/components/admin/grand-finale/finalist-slot
import { WaitlistCard } from '@/components/admin/grand-finale/waitlist-card'
import { FinalistEnrollmentCard } from '@/components/admin/grand-finale/finalist-enrollment-card'
import { FinalDocsReminderButton } from '@/components/admin/grand-finale/final-docs-reminder-button'
import { FinalDocsUploadsToggle } from '@/components/admin/grand-finale/final-docs-uploads-toggle'
import { RankingDashboard } from '@/components/admin/round/ranking-dashboard'
import { CoverageReport } from '@/components/admin/assignment/coverage-report'
import { AssignmentPreviewSheet } from '@/components/admin/assignment/assignment-preview-sheet'
@@ -1530,14 +1531,17 @@ export default function RoundDetailPage() {
{isGrandFinale && programId && (
<>
<FinalistEnrollmentCard programId={programId} roundId={roundId} />
<div className="flex justify-end gap-2">
<Button asChild variant="outline" size="sm">
<Link href="/admin/finals-documents">
<FileText className="mr-2 h-4 w-4" />
Review finalist documents
</Link>
</Button>
<FinalDocsReminderButton programId={programId} />
<div className="flex items-center justify-between gap-2 flex-wrap">
<FinalDocsUploadsToggle roundId={roundId} />
<div className="flex gap-2">
<Button asChild variant="outline" size="sm">
<Link href="/admin/finals-documents">
<FileText className="mr-2 h-4 w-4" />
Review finalist documents
</Link>
</Button>
<FinalDocsReminderButton programId={programId} />
</div>
</div>
<div className="grid gap-4 md:grid-cols-2">
<FinalistSlotsCard programId={programId} />