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:
@@ -64,12 +64,12 @@ import {
|
||||
import { toast } from 'sonner'
|
||||
import { formatDate } from '@/lib/utils'
|
||||
|
||||
type RecipientType = 'ALL' | 'ROLE' | 'STAGE_JURY' | 'PROGRAM_TEAM' | 'USER'
|
||||
type RecipientType = 'ALL' | 'ROLE' | 'ROUND_JURY' | 'PROGRAM_TEAM' | 'USER'
|
||||
|
||||
const RECIPIENT_TYPE_OPTIONS: { value: RecipientType; label: string }[] = [
|
||||
{ value: 'ALL', label: 'All Users' },
|
||||
{ value: 'ROLE', label: 'By Role' },
|
||||
{ value: 'STAGE_JURY', label: 'Stage Jury' },
|
||||
{ value: 'ROUND_JURY', label: 'Round Jury' },
|
||||
{ value: 'PROGRAM_TEAM', label: 'Program Team' },
|
||||
{ value: 'USER', label: 'Specific User' },
|
||||
]
|
||||
@@ -79,7 +79,7 @@ const ROLES = ['JURY_MEMBER', 'MENTOR', 'OBSERVER', 'APPLICANT', 'PROGRAM_ADMIN'
|
||||
export default function MessagesPage() {
|
||||
const [recipientType, setRecipientType] = useState<RecipientType>('ALL')
|
||||
const [selectedRole, setSelectedRole] = useState('')
|
||||
const [stageId, setStageId] = useState('')
|
||||
const [roundId, setStageId] = useState('')
|
||||
const [selectedProgramId, setSelectedProgramId] = useState('')
|
||||
const [selectedUserId, setSelectedUserId] = useState('')
|
||||
const [subject, setSubject] = useState('')
|
||||
@@ -173,10 +173,10 @@ export default function MessagesPage() {
|
||||
const roleLabel = selectedRole ? selectedRole.replace(/_/g, ' ') : ''
|
||||
return roleLabel ? `All ${roleLabel}s` : 'By Role (none selected)'
|
||||
}
|
||||
case 'STAGE_JURY': {
|
||||
if (!stageId) return 'Stage Jury (none selected)'
|
||||
case 'ROUND_JURY': {
|
||||
if (!roundId) return 'Stage Jury (none selected)'
|
||||
const stage = rounds?.find(
|
||||
(r) => r.id === stageId
|
||||
(r) => r.id === roundId
|
||||
)
|
||||
return stage
|
||||
? `Jury of ${stage.program ? `${stage.program.name} - ` : ''}${stage.name}`
|
||||
@@ -217,7 +217,7 @@ export default function MessagesPage() {
|
||||
toast.error('Please select a role')
|
||||
return
|
||||
}
|
||||
if (recipientType === 'STAGE_JURY' && !stageId) {
|
||||
if (recipientType === 'ROUND_JURY' && !roundId) {
|
||||
toast.error('Please select a stage')
|
||||
return
|
||||
}
|
||||
@@ -237,7 +237,7 @@ export default function MessagesPage() {
|
||||
sendMutation.mutate({
|
||||
recipientType,
|
||||
recipientFilter: buildRecipientFilter(),
|
||||
stageId: stageId || undefined,
|
||||
roundId: roundId || undefined,
|
||||
subject: subject.trim(),
|
||||
body: body.trim(),
|
||||
deliveryChannels,
|
||||
@@ -332,10 +332,10 @@ export default function MessagesPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{recipientType === 'STAGE_JURY' && (
|
||||
{recipientType === 'ROUND_JURY' && (
|
||||
<div className="space-y-2">
|
||||
<Label>Select Stage</Label>
|
||||
<Select value={stageId} onValueChange={setStageId}>
|
||||
<Select value={roundId} onValueChange={setStageId}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Choose a stage..." />
|
||||
</SelectTrigger>
|
||||
|
||||
Reference in New Issue
Block a user