2026-02-14 15:26:42 +01:00
|
|
|
import { z } from 'zod'
|
|
|
|
|
import { router, adminProcedure } from '../trpc'
|
Redesign admin dashboard: pipeline view, round-specific stats, smart actions
Complete rewrite of the admin dashboard replacing the 1056-line monolith with
modular components. Key improvements:
- Competition pipeline: horizontal visualization of all rounds in pipeline order
(by sortOrder, not creation date) with type-specific icons and metrics
- Round-specific stats: stat cards dynamically change based on active round type
(INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION
shows assignments/completion, fallback shows generic project/jury stats)
- Smart actions: context-aware "Action Required" panel that only flags the next
draft round (not all), only flags unassigned projects for EVALUATION rounds,
includes deadline warnings with severity levels (critical/warning/info)
- Active round panel: detailed view with project state bar, type-specific content,
and deadline countdown
- Extracted components: project list, activity feed, category breakdown, skeleton
Backend enriched with 17 parallel queries building rich PipelineRound data
including per-round project states, eval stats, filtering stats, live session
status, and deliberation counts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:12:28 +01:00
|
|
|
import type { RoundType, RoundStatus, ProjectRoundStateValue } from '@prisma/client'
|
|
|
|
|
|
|
|
|
|
// ─── Types ──────────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
type ProjectStateCounts = {
|
|
|
|
|
PENDING: number
|
|
|
|
|
IN_PROGRESS: number
|
|
|
|
|
PASSED: number
|
|
|
|
|
REJECTED: number
|
|
|
|
|
COMPLETED: number
|
|
|
|
|
WITHDRAWN: number
|
|
|
|
|
total: number
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type PipelineRound = {
|
|
|
|
|
id: string
|
|
|
|
|
name: string
|
|
|
|
|
slug: string
|
|
|
|
|
roundType: RoundType
|
|
|
|
|
status: RoundStatus
|
|
|
|
|
sortOrder: number
|
|
|
|
|
windowOpenAt: Date | null
|
|
|
|
|
windowCloseAt: Date | null
|
|
|
|
|
projectStates: ProjectStateCounts
|
|
|
|
|
assignmentCount: number
|
|
|
|
|
evalSubmitted: number
|
|
|
|
|
evalDraft: number
|
|
|
|
|
evalTotal: number
|
|
|
|
|
filteringPassed: number
|
|
|
|
|
filteringRejected: number
|
|
|
|
|
filteringFlagged: number
|
|
|
|
|
filteringTotal: number
|
|
|
|
|
liveSessionStatus: string | null
|
|
|
|
|
deliberationCount: number
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type DashboardAction = {
|
|
|
|
|
id: string
|
|
|
|
|
severity: 'critical' | 'warning' | 'info'
|
|
|
|
|
title: string
|
|
|
|
|
description: string
|
|
|
|
|
href: string
|
|
|
|
|
roundId?: string
|
|
|
|
|
roundType?: RoundType
|
|
|
|
|
count?: number
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
function emptyStateCounts(): ProjectStateCounts {
|
|
|
|
|
return { PENDING: 0, IN_PROGRESS: 0, PASSED: 0, REJECTED: 0, COMPLETED: 0, WITHDRAWN: 0, total: 0 }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function daysUntil(date: Date): number {
|
|
|
|
|
return Math.ceil((date.getTime() - Date.now()) / (1000 * 60 * 60 * 24))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function formatRoundType(rt: RoundType): string {
|
|
|
|
|
return rt.replace(/_/g, ' ').toLowerCase().replace(/\b\w/g, (c) => c.toUpperCase())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ─── Router ──────────────────────────────────────────────────────────────────
|
2026-02-14 15:26:42 +01:00
|
|
|
|
|
|
|
|
export const dashboardRouter = router({
|
|
|
|
|
/**
|
|
|
|
|
* Get all dashboard stats in a single query batch.
|
Redesign admin dashboard: pipeline view, round-specific stats, smart actions
Complete rewrite of the admin dashboard replacing the 1056-line monolith with
modular components. Key improvements:
- Competition pipeline: horizontal visualization of all rounds in pipeline order
(by sortOrder, not creation date) with type-specific icons and metrics
- Round-specific stats: stat cards dynamically change based on active round type
(INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION
shows assignments/completion, fallback shows generic project/jury stats)
- Smart actions: context-aware "Action Required" panel that only flags the next
draft round (not all), only flags unassigned projects for EVALUATION rounds,
includes deadline warnings with severity levels (critical/warning/info)
- Active round panel: detailed view with project state bar, type-specific content,
and deadline countdown
- Extracted components: project list, activity feed, category breakdown, skeleton
Backend enriched with 17 parallel queries building rich PipelineRound data
including per-round project states, eval stats, filtering stats, live session
status, and deliberation counts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:12:28 +01:00
|
|
|
* Returns pipeline rounds, smart actions, and supporting data.
|
2026-02-14 15:26:42 +01:00
|
|
|
*/
|
|
|
|
|
getStats: adminProcedure
|
|
|
|
|
.input(z.object({ editionId: z.string() }))
|
|
|
|
|
.query(async ({ ctx, input }) => {
|
|
|
|
|
const { editionId } = input
|
|
|
|
|
|
|
|
|
|
const edition = await ctx.prisma.program.findUnique({
|
|
|
|
|
where: { id: editionId },
|
|
|
|
|
select: { name: true, year: true },
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if (!edition) return null
|
|
|
|
|
|
|
|
|
|
const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)
|
|
|
|
|
|
Redesign admin dashboard: pipeline view, round-specific stats, smart actions
Complete rewrite of the admin dashboard replacing the 1056-line monolith with
modular components. Key improvements:
- Competition pipeline: horizontal visualization of all rounds in pipeline order
(by sortOrder, not creation date) with type-specific icons and metrics
- Round-specific stats: stat cards dynamically change based on active round type
(INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION
shows assignments/completion, fallback shows generic project/jury stats)
- Smart actions: context-aware "Action Required" panel that only flags the next
draft round (not all), only flags unassigned projects for EVALUATION rounds,
includes deadline warnings with severity levels (critical/warning/info)
- Active round panel: detailed view with project state bar, type-specific content,
and deadline countdown
- Extracted components: project list, activity feed, category breakdown, skeleton
Backend enriched with 17 parallel queries building rich PipelineRound data
including per-round project states, eval stats, filtering stats, live session
status, and deliberation counts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:12:28 +01:00
|
|
|
// ── All queries in parallel ──────────────────────────────────────
|
|
|
|
|
|
2026-02-14 15:26:42 +01:00
|
|
|
const [
|
Redesign admin dashboard: pipeline view, round-specific stats, smart actions
Complete rewrite of the admin dashboard replacing the 1056-line monolith with
modular components. Key improvements:
- Competition pipeline: horizontal visualization of all rounds in pipeline order
(by sortOrder, not creation date) with type-specific icons and metrics
- Round-specific stats: stat cards dynamically change based on active round type
(INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION
shows assignments/completion, fallback shows generic project/jury stats)
- Smart actions: context-aware "Action Required" panel that only flags the next
draft round (not all), only flags unassigned projects for EVALUATION rounds,
includes deadline warnings with severity levels (critical/warning/info)
- Active round panel: detailed view with project state bar, type-specific content,
and deadline countdown
- Extracted components: project list, activity feed, category breakdown, skeleton
Backend enriched with 17 parallel queries building rich PipelineRound data
including per-round project states, eval stats, filtering stats, live session
status, and deliberation counts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:12:28 +01:00
|
|
|
// Pipeline rounds (all, ordered by sortOrder)
|
|
|
|
|
allRounds,
|
|
|
|
|
// Per-round project state breakdown
|
|
|
|
|
stateBreakdown,
|
|
|
|
|
// Per-round eval data (assignments with eval status)
|
|
|
|
|
roundEvalData,
|
|
|
|
|
// Per-round filtering results
|
|
|
|
|
filteringStats,
|
|
|
|
|
// Live session statuses
|
|
|
|
|
liveSessions,
|
|
|
|
|
// Deliberation session counts
|
|
|
|
|
deliberationCounts,
|
|
|
|
|
// Summary counts
|
2026-02-14 15:26:42 +01:00
|
|
|
projectCount,
|
|
|
|
|
newProjectsThisWeek,
|
|
|
|
|
totalJurors,
|
|
|
|
|
activeJurors,
|
|
|
|
|
evaluationStats,
|
|
|
|
|
totalAssignments,
|
Redesign admin dashboard: pipeline view, round-specific stats, smart actions
Complete rewrite of the admin dashboard replacing the 1056-line monolith with
modular components. Key improvements:
- Competition pipeline: horizontal visualization of all rounds in pipeline order
(by sortOrder, not creation date) with type-specific icons and metrics
- Round-specific stats: stat cards dynamically change based on active round type
(INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION
shows assignments/completion, fallback shows generic project/jury stats)
- Smart actions: context-aware "Action Required" panel that only flags the next
draft round (not all), only flags unassigned projects for EVALUATION rounds,
includes deadline warnings with severity levels (critical/warning/info)
- Active round panel: detailed view with project state bar, type-specific content,
and deadline countdown
- Extracted components: project list, activity feed, category breakdown, skeleton
Backend enriched with 17 parallel queries building rich PipelineRound data
including per-round project states, eval stats, filtering stats, live session
status, and deliberation counts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:12:28 +01:00
|
|
|
// Lists
|
2026-02-14 15:26:42 +01:00
|
|
|
latestProjects,
|
|
|
|
|
categoryBreakdown,
|
|
|
|
|
oceanIssueBreakdown,
|
|
|
|
|
recentActivity,
|
Redesign admin dashboard: pipeline view, round-specific stats, smart actions
Complete rewrite of the admin dashboard replacing the 1056-line monolith with
modular components. Key improvements:
- Competition pipeline: horizontal visualization of all rounds in pipeline order
(by sortOrder, not creation date) with type-specific icons and metrics
- Round-specific stats: stat cards dynamically change based on active round type
(INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION
shows assignments/completion, fallback shows generic project/jury stats)
- Smart actions: context-aware "Action Required" panel that only flags the next
draft round (not all), only flags unassigned projects for EVALUATION rounds,
includes deadline warnings with severity levels (critical/warning/info)
- Active round panel: detailed view with project state bar, type-specific content,
and deadline countdown
- Extracted components: project list, activity feed, category breakdown, skeleton
Backend enriched with 17 parallel queries building rich PipelineRound data
including per-round project states, eval stats, filtering stats, live session
status, and deliberation counts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:12:28 +01:00
|
|
|
// Action signals
|
2026-02-14 15:26:42 +01:00
|
|
|
pendingCOIs,
|
|
|
|
|
] = await Promise.all([
|
Redesign admin dashboard: pipeline view, round-specific stats, smart actions
Complete rewrite of the admin dashboard replacing the 1056-line monolith with
modular components. Key improvements:
- Competition pipeline: horizontal visualization of all rounds in pipeline order
(by sortOrder, not creation date) with type-specific icons and metrics
- Round-specific stats: stat cards dynamically change based on active round type
(INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION
shows assignments/completion, fallback shows generic project/jury stats)
- Smart actions: context-aware "Action Required" panel that only flags the next
draft round (not all), only flags unassigned projects for EVALUATION rounds,
includes deadline warnings with severity levels (critical/warning/info)
- Active round panel: detailed view with project state bar, type-specific content,
and deadline countdown
- Extracted components: project list, activity feed, category breakdown, skeleton
Backend enriched with 17 parallel queries building rich PipelineRound data
including per-round project states, eval stats, filtering stats, live session
status, and deliberation counts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:12:28 +01:00
|
|
|
// 1. All pipeline rounds
|
|
|
|
|
ctx.prisma.round.findMany({
|
|
|
|
|
where: { competition: { programId: editionId } },
|
|
|
|
|
orderBy: { sortOrder: 'asc' },
|
|
|
|
|
select: {
|
|
|
|
|
id: true,
|
|
|
|
|
name: true,
|
|
|
|
|
slug: true,
|
|
|
|
|
roundType: true,
|
|
|
|
|
status: true,
|
|
|
|
|
sortOrder: true,
|
|
|
|
|
windowOpenAt: true,
|
|
|
|
|
windowCloseAt: true,
|
|
|
|
|
_count: {
|
|
|
|
|
select: {
|
|
|
|
|
projectRoundStates: true,
|
|
|
|
|
assignments: true,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
|
|
// 2. Per-round project state counts
|
|
|
|
|
ctx.prisma.projectRoundState.groupBy({
|
|
|
|
|
by: ['roundId', 'state'],
|
|
|
|
|
where: { round: { competition: { programId: editionId } } },
|
|
|
|
|
_count: true,
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
|
|
// 3. Assignments with eval status (for per-round eval aggregation)
|
|
|
|
|
ctx.prisma.assignment.findMany({
|
|
|
|
|
where: { round: { competition: { programId: editionId } } },
|
|
|
|
|
select: {
|
|
|
|
|
roundId: true,
|
|
|
|
|
evaluation: { select: { status: true } },
|
|
|
|
|
},
|
2026-02-14 15:26:42 +01:00
|
|
|
}),
|
Redesign admin dashboard: pipeline view, round-specific stats, smart actions
Complete rewrite of the admin dashboard replacing the 1056-line monolith with
modular components. Key improvements:
- Competition pipeline: horizontal visualization of all rounds in pipeline order
(by sortOrder, not creation date) with type-specific icons and metrics
- Round-specific stats: stat cards dynamically change based on active round type
(INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION
shows assignments/completion, fallback shows generic project/jury stats)
- Smart actions: context-aware "Action Required" panel that only flags the next
draft round (not all), only flags unassigned projects for EVALUATION rounds,
includes deadline warnings with severity levels (critical/warning/info)
- Active round panel: detailed view with project state bar, type-specific content,
and deadline countdown
- Extracted components: project list, activity feed, category breakdown, skeleton
Backend enriched with 17 parallel queries building rich PipelineRound data
including per-round project states, eval stats, filtering stats, live session
status, and deliberation counts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:12:28 +01:00
|
|
|
|
|
|
|
|
// 4. Filtering results per round
|
|
|
|
|
ctx.prisma.filteringResult.groupBy({
|
|
|
|
|
by: ['roundId', 'outcome'],
|
|
|
|
|
where: { round: { competition: { programId: editionId } } },
|
|
|
|
|
_count: true,
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
|
|
// 5. Live session statuses
|
|
|
|
|
ctx.prisma.liveVotingSession.findMany({
|
|
|
|
|
where: { round: { competition: { programId: editionId } } },
|
|
|
|
|
select: { roundId: true, status: true },
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
|
|
// 6. Deliberation session counts
|
|
|
|
|
ctx.prisma.deliberationSession.groupBy({
|
|
|
|
|
by: ['roundId'],
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
where: { competition: { programId: editionId } },
|
Redesign admin dashboard: pipeline view, round-specific stats, smart actions
Complete rewrite of the admin dashboard replacing the 1056-line monolith with
modular components. Key improvements:
- Competition pipeline: horizontal visualization of all rounds in pipeline order
(by sortOrder, not creation date) with type-specific icons and metrics
- Round-specific stats: stat cards dynamically change based on active round type
(INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION
shows assignments/completion, fallback shows generic project/jury stats)
- Smart actions: context-aware "Action Required" panel that only flags the next
draft round (not all), only flags unassigned projects for EVALUATION rounds,
includes deadline warnings with severity levels (critical/warning/info)
- Active round panel: detailed view with project state bar, type-specific content,
and deadline countdown
- Extracted components: project list, activity feed, category breakdown, skeleton
Backend enriched with 17 parallel queries building rich PipelineRound data
including per-round project states, eval stats, filtering stats, live session
status, and deliberation counts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:12:28 +01:00
|
|
|
_count: true,
|
2026-02-14 15:26:42 +01:00
|
|
|
}),
|
Redesign admin dashboard: pipeline view, round-specific stats, smart actions
Complete rewrite of the admin dashboard replacing the 1056-line monolith with
modular components. Key improvements:
- Competition pipeline: horizontal visualization of all rounds in pipeline order
(by sortOrder, not creation date) with type-specific icons and metrics
- Round-specific stats: stat cards dynamically change based on active round type
(INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION
shows assignments/completion, fallback shows generic project/jury stats)
- Smart actions: context-aware "Action Required" panel that only flags the next
draft round (not all), only flags unassigned projects for EVALUATION rounds,
includes deadline warnings with severity levels (critical/warning/info)
- Active round panel: detailed view with project state bar, type-specific content,
and deadline countdown
- Extracted components: project list, activity feed, category breakdown, skeleton
Backend enriched with 17 parallel queries building rich PipelineRound data
including per-round project states, eval stats, filtering stats, live session
status, and deliberation counts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:12:28 +01:00
|
|
|
|
|
|
|
|
// 7. Project count
|
2026-02-14 15:26:42 +01:00
|
|
|
ctx.prisma.project.count({
|
|
|
|
|
where: { programId: editionId },
|
|
|
|
|
}),
|
Redesign admin dashboard: pipeline view, round-specific stats, smart actions
Complete rewrite of the admin dashboard replacing the 1056-line monolith with
modular components. Key improvements:
- Competition pipeline: horizontal visualization of all rounds in pipeline order
(by sortOrder, not creation date) with type-specific icons and metrics
- Round-specific stats: stat cards dynamically change based on active round type
(INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION
shows assignments/completion, fallback shows generic project/jury stats)
- Smart actions: context-aware "Action Required" panel that only flags the next
draft round (not all), only flags unassigned projects for EVALUATION rounds,
includes deadline warnings with severity levels (critical/warning/info)
- Active round panel: detailed view with project state bar, type-specific content,
and deadline countdown
- Extracted components: project list, activity feed, category breakdown, skeleton
Backend enriched with 17 parallel queries building rich PipelineRound data
including per-round project states, eval stats, filtering stats, live session
status, and deliberation counts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:12:28 +01:00
|
|
|
|
|
|
|
|
// 8. New projects this week
|
2026-02-14 15:26:42 +01:00
|
|
|
ctx.prisma.project.count({
|
Redesign admin dashboard: pipeline view, round-specific stats, smart actions
Complete rewrite of the admin dashboard replacing the 1056-line monolith with
modular components. Key improvements:
- Competition pipeline: horizontal visualization of all rounds in pipeline order
(by sortOrder, not creation date) with type-specific icons and metrics
- Round-specific stats: stat cards dynamically change based on active round type
(INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION
shows assignments/completion, fallback shows generic project/jury stats)
- Smart actions: context-aware "Action Required" panel that only flags the next
draft round (not all), only flags unassigned projects for EVALUATION rounds,
includes deadline warnings with severity levels (critical/warning/info)
- Active round panel: detailed view with project state bar, type-specific content,
and deadline countdown
- Extracted components: project list, activity feed, category breakdown, skeleton
Backend enriched with 17 parallel queries building rich PipelineRound data
including per-round project states, eval stats, filtering stats, live session
status, and deliberation counts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:12:28 +01:00
|
|
|
where: { programId: editionId, createdAt: { gte: sevenDaysAgo } },
|
2026-02-14 15:26:42 +01:00
|
|
|
}),
|
Redesign admin dashboard: pipeline view, round-specific stats, smart actions
Complete rewrite of the admin dashboard replacing the 1056-line monolith with
modular components. Key improvements:
- Competition pipeline: horizontal visualization of all rounds in pipeline order
(by sortOrder, not creation date) with type-specific icons and metrics
- Round-specific stats: stat cards dynamically change based on active round type
(INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION
shows assignments/completion, fallback shows generic project/jury stats)
- Smart actions: context-aware "Action Required" panel that only flags the next
draft round (not all), only flags unassigned projects for EVALUATION rounds,
includes deadline warnings with severity levels (critical/warning/info)
- Active round panel: detailed view with project state bar, type-specific content,
and deadline countdown
- Extracted components: project list, activity feed, category breakdown, skeleton
Backend enriched with 17 parallel queries building rich PipelineRound data
including per-round project states, eval stats, filtering stats, live session
status, and deliberation counts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:12:28 +01:00
|
|
|
|
|
|
|
|
// 9. Total jurors
|
2026-02-14 15:26:42 +01:00
|
|
|
ctx.prisma.user.count({
|
|
|
|
|
where: {
|
|
|
|
|
role: 'JURY_MEMBER',
|
|
|
|
|
status: { in: ['ACTIVE', 'INVITED', 'NONE'] },
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
assignments: { some: { round: { competition: { programId: editionId } } } },
|
2026-02-14 15:26:42 +01:00
|
|
|
},
|
|
|
|
|
}),
|
Redesign admin dashboard: pipeline view, round-specific stats, smart actions
Complete rewrite of the admin dashboard replacing the 1056-line monolith with
modular components. Key improvements:
- Competition pipeline: horizontal visualization of all rounds in pipeline order
(by sortOrder, not creation date) with type-specific icons and metrics
- Round-specific stats: stat cards dynamically change based on active round type
(INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION
shows assignments/completion, fallback shows generic project/jury stats)
- Smart actions: context-aware "Action Required" panel that only flags the next
draft round (not all), only flags unassigned projects for EVALUATION rounds,
includes deadline warnings with severity levels (critical/warning/info)
- Active round panel: detailed view with project state bar, type-specific content,
and deadline countdown
- Extracted components: project list, activity feed, category breakdown, skeleton
Backend enriched with 17 parallel queries building rich PipelineRound data
including per-round project states, eval stats, filtering stats, live session
status, and deliberation counts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:12:28 +01:00
|
|
|
|
|
|
|
|
// 10. Active jurors
|
2026-02-14 15:26:42 +01:00
|
|
|
ctx.prisma.user.count({
|
|
|
|
|
where: {
|
|
|
|
|
role: 'JURY_MEMBER',
|
|
|
|
|
status: 'ACTIVE',
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
assignments: { some: { round: { competition: { programId: editionId } } } },
|
2026-02-14 15:26:42 +01:00
|
|
|
},
|
|
|
|
|
}),
|
Redesign admin dashboard: pipeline view, round-specific stats, smart actions
Complete rewrite of the admin dashboard replacing the 1056-line monolith with
modular components. Key improvements:
- Competition pipeline: horizontal visualization of all rounds in pipeline order
(by sortOrder, not creation date) with type-specific icons and metrics
- Round-specific stats: stat cards dynamically change based on active round type
(INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION
shows assignments/completion, fallback shows generic project/jury stats)
- Smart actions: context-aware "Action Required" panel that only flags the next
draft round (not all), only flags unassigned projects for EVALUATION rounds,
includes deadline warnings with severity levels (critical/warning/info)
- Active round panel: detailed view with project state bar, type-specific content,
and deadline countdown
- Extracted components: project list, activity feed, category breakdown, skeleton
Backend enriched with 17 parallel queries building rich PipelineRound data
including per-round project states, eval stats, filtering stats, live session
status, and deliberation counts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:12:28 +01:00
|
|
|
|
|
|
|
|
// 11. Global evaluation stats
|
2026-02-14 15:26:42 +01:00
|
|
|
ctx.prisma.evaluation.groupBy({
|
|
|
|
|
by: ['status'],
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
where: { assignment: { round: { competition: { programId: editionId } } } },
|
2026-02-14 15:26:42 +01:00
|
|
|
_count: true,
|
|
|
|
|
}),
|
Redesign admin dashboard: pipeline view, round-specific stats, smart actions
Complete rewrite of the admin dashboard replacing the 1056-line monolith with
modular components. Key improvements:
- Competition pipeline: horizontal visualization of all rounds in pipeline order
(by sortOrder, not creation date) with type-specific icons and metrics
- Round-specific stats: stat cards dynamically change based on active round type
(INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION
shows assignments/completion, fallback shows generic project/jury stats)
- Smart actions: context-aware "Action Required" panel that only flags the next
draft round (not all), only flags unassigned projects for EVALUATION rounds,
includes deadline warnings with severity levels (critical/warning/info)
- Active round panel: detailed view with project state bar, type-specific content,
and deadline countdown
- Extracted components: project list, activity feed, category breakdown, skeleton
Backend enriched with 17 parallel queries building rich PipelineRound data
including per-round project states, eval stats, filtering stats, live session
status, and deliberation counts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:12:28 +01:00
|
|
|
|
|
|
|
|
// 12. Total assignments
|
2026-02-14 15:26:42 +01:00
|
|
|
ctx.prisma.assignment.count({
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
where: { round: { competition: { programId: editionId } } },
|
2026-02-14 15:26:42 +01:00
|
|
|
}),
|
Redesign admin dashboard: pipeline view, round-specific stats, smart actions
Complete rewrite of the admin dashboard replacing the 1056-line monolith with
modular components. Key improvements:
- Competition pipeline: horizontal visualization of all rounds in pipeline order
(by sortOrder, not creation date) with type-specific icons and metrics
- Round-specific stats: stat cards dynamically change based on active round type
(INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION
shows assignments/completion, fallback shows generic project/jury stats)
- Smart actions: context-aware "Action Required" panel that only flags the next
draft round (not all), only flags unassigned projects for EVALUATION rounds,
includes deadline warnings with severity levels (critical/warning/info)
- Active round panel: detailed view with project state bar, type-specific content,
and deadline countdown
- Extracted components: project list, activity feed, category breakdown, skeleton
Backend enriched with 17 parallel queries building rich PipelineRound data
including per-round project states, eval stats, filtering stats, live session
status, and deliberation counts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:12:28 +01:00
|
|
|
|
|
|
|
|
// 13. Latest projects
|
2026-02-14 15:26:42 +01:00
|
|
|
ctx.prisma.project.findMany({
|
|
|
|
|
where: { programId: editionId },
|
|
|
|
|
orderBy: { createdAt: 'desc' },
|
|
|
|
|
take: 8,
|
|
|
|
|
select: {
|
|
|
|
|
id: true,
|
|
|
|
|
title: true,
|
|
|
|
|
teamName: true,
|
|
|
|
|
country: true,
|
|
|
|
|
competitionCategory: true,
|
|
|
|
|
oceanIssue: true,
|
|
|
|
|
logoKey: true,
|
|
|
|
|
createdAt: true,
|
|
|
|
|
submittedAt: true,
|
|
|
|
|
status: true,
|
|
|
|
|
},
|
|
|
|
|
}),
|
Redesign admin dashboard: pipeline view, round-specific stats, smart actions
Complete rewrite of the admin dashboard replacing the 1056-line monolith with
modular components. Key improvements:
- Competition pipeline: horizontal visualization of all rounds in pipeline order
(by sortOrder, not creation date) with type-specific icons and metrics
- Round-specific stats: stat cards dynamically change based on active round type
(INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION
shows assignments/completion, fallback shows generic project/jury stats)
- Smart actions: context-aware "Action Required" panel that only flags the next
draft round (not all), only flags unassigned projects for EVALUATION rounds,
includes deadline warnings with severity levels (critical/warning/info)
- Active round panel: detailed view with project state bar, type-specific content,
and deadline countdown
- Extracted components: project list, activity feed, category breakdown, skeleton
Backend enriched with 17 parallel queries building rich PipelineRound data
including per-round project states, eval stats, filtering stats, live session
status, and deliberation counts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:12:28 +01:00
|
|
|
|
|
|
|
|
// 14. Category breakdown
|
2026-02-14 15:26:42 +01:00
|
|
|
ctx.prisma.project.groupBy({
|
|
|
|
|
by: ['competitionCategory'],
|
|
|
|
|
where: { programId: editionId },
|
|
|
|
|
_count: true,
|
|
|
|
|
}),
|
Redesign admin dashboard: pipeline view, round-specific stats, smart actions
Complete rewrite of the admin dashboard replacing the 1056-line monolith with
modular components. Key improvements:
- Competition pipeline: horizontal visualization of all rounds in pipeline order
(by sortOrder, not creation date) with type-specific icons and metrics
- Round-specific stats: stat cards dynamically change based on active round type
(INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION
shows assignments/completion, fallback shows generic project/jury stats)
- Smart actions: context-aware "Action Required" panel that only flags the next
draft round (not all), only flags unassigned projects for EVALUATION rounds,
includes deadline warnings with severity levels (critical/warning/info)
- Active round panel: detailed view with project state bar, type-specific content,
and deadline countdown
- Extracted components: project list, activity feed, category breakdown, skeleton
Backend enriched with 17 parallel queries building rich PipelineRound data
including per-round project states, eval stats, filtering stats, live session
status, and deliberation counts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:12:28 +01:00
|
|
|
|
|
|
|
|
// 15. Ocean issue breakdown
|
2026-02-14 15:26:42 +01:00
|
|
|
ctx.prisma.project.groupBy({
|
|
|
|
|
by: ['oceanIssue'],
|
|
|
|
|
where: { programId: editionId },
|
|
|
|
|
_count: true,
|
|
|
|
|
}),
|
Redesign admin dashboard: pipeline view, round-specific stats, smart actions
Complete rewrite of the admin dashboard replacing the 1056-line monolith with
modular components. Key improvements:
- Competition pipeline: horizontal visualization of all rounds in pipeline order
(by sortOrder, not creation date) with type-specific icons and metrics
- Round-specific stats: stat cards dynamically change based on active round type
(INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION
shows assignments/completion, fallback shows generic project/jury stats)
- Smart actions: context-aware "Action Required" panel that only flags the next
draft round (not all), only flags unassigned projects for EVALUATION rounds,
includes deadline warnings with severity levels (critical/warning/info)
- Active round panel: detailed view with project state bar, type-specific content,
and deadline countdown
- Extracted components: project list, activity feed, category breakdown, skeleton
Backend enriched with 17 parallel queries building rich PipelineRound data
including per-round project states, eval stats, filtering stats, live session
status, and deliberation counts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:12:28 +01:00
|
|
|
|
|
|
|
|
// 16. Recent activity
|
2026-02-14 15:26:42 +01:00
|
|
|
ctx.prisma.auditLog.findMany({
|
Redesign admin dashboard: pipeline view, round-specific stats, smart actions
Complete rewrite of the admin dashboard replacing the 1056-line monolith with
modular components. Key improvements:
- Competition pipeline: horizontal visualization of all rounds in pipeline order
(by sortOrder, not creation date) with type-specific icons and metrics
- Round-specific stats: stat cards dynamically change based on active round type
(INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION
shows assignments/completion, fallback shows generic project/jury stats)
- Smart actions: context-aware "Action Required" panel that only flags the next
draft round (not all), only flags unassigned projects for EVALUATION rounds,
includes deadline warnings with severity levels (critical/warning/info)
- Active round panel: detailed view with project state bar, type-specific content,
and deadline countdown
- Extracted components: project list, activity feed, category breakdown, skeleton
Backend enriched with 17 parallel queries building rich PipelineRound data
including per-round project states, eval stats, filtering stats, live session
status, and deliberation counts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:12:28 +01:00
|
|
|
where: { timestamp: { gte: sevenDaysAgo } },
|
2026-02-14 15:26:42 +01:00
|
|
|
orderBy: { timestamp: 'desc' },
|
|
|
|
|
take: 8,
|
|
|
|
|
select: {
|
|
|
|
|
id: true,
|
|
|
|
|
action: true,
|
|
|
|
|
entityType: true,
|
|
|
|
|
timestamp: true,
|
|
|
|
|
user: { select: { name: true } },
|
|
|
|
|
},
|
|
|
|
|
}),
|
Redesign admin dashboard: pipeline view, round-specific stats, smart actions
Complete rewrite of the admin dashboard replacing the 1056-line monolith with
modular components. Key improvements:
- Competition pipeline: horizontal visualization of all rounds in pipeline order
(by sortOrder, not creation date) with type-specific icons and metrics
- Round-specific stats: stat cards dynamically change based on active round type
(INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION
shows assignments/completion, fallback shows generic project/jury stats)
- Smart actions: context-aware "Action Required" panel that only flags the next
draft round (not all), only flags unassigned projects for EVALUATION rounds,
includes deadline warnings with severity levels (critical/warning/info)
- Active round panel: detailed view with project state bar, type-specific content,
and deadline countdown
- Extracted components: project list, activity feed, category breakdown, skeleton
Backend enriched with 17 parallel queries building rich PipelineRound data
including per-round project states, eval stats, filtering stats, live session
status, and deliberation counts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:12:28 +01:00
|
|
|
|
|
|
|
|
// 17. Pending COIs
|
2026-02-14 15:26:42 +01:00
|
|
|
ctx.prisma.conflictOfInterest.count({
|
|
|
|
|
where: {
|
|
|
|
|
hasConflict: true,
|
|
|
|
|
reviewedAt: null,
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
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>
2026-02-15 23:04:15 +01:00
|
|
|
assignment: { round: { competition: { programId: editionId } } },
|
2026-02-14 15:26:42 +01:00
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
])
|
|
|
|
|
|
Redesign admin dashboard: pipeline view, round-specific stats, smart actions
Complete rewrite of the admin dashboard replacing the 1056-line monolith with
modular components. Key improvements:
- Competition pipeline: horizontal visualization of all rounds in pipeline order
(by sortOrder, not creation date) with type-specific icons and metrics
- Round-specific stats: stat cards dynamically change based on active round type
(INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION
shows assignments/completion, fallback shows generic project/jury stats)
- Smart actions: context-aware "Action Required" panel that only flags the next
draft round (not all), only flags unassigned projects for EVALUATION rounds,
includes deadline warnings with severity levels (critical/warning/info)
- Active round panel: detailed view with project state bar, type-specific content,
and deadline countdown
- Extracted components: project list, activity feed, category breakdown, skeleton
Backend enriched with 17 parallel queries building rich PipelineRound data
including per-round project states, eval stats, filtering stats, live session
status, and deliberation counts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:12:28 +01:00
|
|
|
// ── Assemble pipeline rounds ────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
// Build state counts map: roundId -> ProjectStateCounts
|
|
|
|
|
const stateMap = new Map<string, ProjectStateCounts>()
|
|
|
|
|
for (const row of stateBreakdown) {
|
|
|
|
|
if (!stateMap.has(row.roundId)) stateMap.set(row.roundId, emptyStateCounts())
|
|
|
|
|
const counts = stateMap.get(row.roundId)!
|
|
|
|
|
const state = row.state as ProjectRoundStateValue
|
|
|
|
|
if (state in counts) {
|
|
|
|
|
counts[state as keyof Omit<ProjectStateCounts, 'total'>] = row._count
|
|
|
|
|
counts.total += row._count
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Build eval map: roundId -> { submitted, draft, total }
|
|
|
|
|
const evalMap = new Map<string, { submitted: number; draft: number; total: number }>()
|
|
|
|
|
for (const a of roundEvalData) {
|
|
|
|
|
if (!evalMap.has(a.roundId)) evalMap.set(a.roundId, { submitted: 0, draft: 0, total: 0 })
|
|
|
|
|
const entry = evalMap.get(a.roundId)!
|
|
|
|
|
entry.total++
|
|
|
|
|
if (a.evaluation?.status === 'SUBMITTED') entry.submitted++
|
|
|
|
|
else if (a.evaluation?.status === 'DRAFT') entry.draft++
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Build filtering map: roundId -> { passed, rejected, flagged, total }
|
|
|
|
|
const filterMap = new Map<string, { passed: number; rejected: number; flagged: number; total: number }>()
|
|
|
|
|
for (const row of filteringStats) {
|
|
|
|
|
if (!filterMap.has(row.roundId)) filterMap.set(row.roundId, { passed: 0, rejected: 0, flagged: 0, total: 0 })
|
|
|
|
|
const entry = filterMap.get(row.roundId)!
|
|
|
|
|
entry.total += row._count
|
|
|
|
|
if (row.outcome === 'PASSED') entry.passed = row._count
|
|
|
|
|
else if (row.outcome === 'FILTERED_OUT') entry.rejected = row._count
|
|
|
|
|
else if (row.outcome === 'FLAGGED') entry.flagged = row._count
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Build live session map: roundId -> status
|
|
|
|
|
const liveMap = new Map<string, string>()
|
|
|
|
|
for (const s of liveSessions) {
|
|
|
|
|
if (s.roundId) liveMap.set(s.roundId, s.status)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Build deliberation map: roundId -> count
|
|
|
|
|
const delibMap = new Map<string, number>()
|
|
|
|
|
for (const row of deliberationCounts) {
|
|
|
|
|
delibMap.set(row.roundId, row._count)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Assemble pipeline rounds
|
|
|
|
|
const pipelineRounds: PipelineRound[] = allRounds.map((round) => {
|
|
|
|
|
const states = stateMap.get(round.id) ?? emptyStateCounts()
|
|
|
|
|
const evals = evalMap.get(round.id) ?? { submitted: 0, draft: 0, total: 0 }
|
|
|
|
|
const filters = filterMap.get(round.id) ?? { passed: 0, rejected: 0, flagged: 0, total: 0 }
|
|
|
|
|
return {
|
|
|
|
|
id: round.id,
|
|
|
|
|
name: round.name,
|
|
|
|
|
slug: round.slug,
|
|
|
|
|
roundType: round.roundType,
|
|
|
|
|
status: round.status,
|
|
|
|
|
sortOrder: round.sortOrder,
|
|
|
|
|
windowOpenAt: round.windowOpenAt,
|
|
|
|
|
windowCloseAt: round.windowCloseAt,
|
|
|
|
|
projectStates: states,
|
|
|
|
|
assignmentCount: round._count.assignments,
|
|
|
|
|
evalSubmitted: evals.submitted,
|
|
|
|
|
evalDraft: evals.draft,
|
|
|
|
|
evalTotal: evals.total,
|
|
|
|
|
filteringPassed: filters.passed,
|
|
|
|
|
filteringRejected: filters.rejected,
|
|
|
|
|
filteringFlagged: filters.flagged,
|
|
|
|
|
filteringTotal: filters.total,
|
|
|
|
|
liveSessionStatus: liveMap.get(round.id) ?? null,
|
|
|
|
|
deliberationCount: delibMap.get(round.id) ?? 0,
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// ── Determine active round ──────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
const activeRound = pipelineRounds.find((r) => r.status === 'ROUND_ACTIVE') ?? null
|
|
|
|
|
const activeRoundId = activeRound?.id ?? null
|
|
|
|
|
|
|
|
|
|
// ── Compute smart actions ───────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
const nextActions: DashboardAction[] = []
|
|
|
|
|
const activeRounds = pipelineRounds.filter((r) => r.status === 'ROUND_ACTIVE')
|
|
|
|
|
const lastActiveSortOrder = Math.max(...activeRounds.map((r) => r.sortOrder), -1)
|
|
|
|
|
|
|
|
|
|
// 1. Next draft round (only the first one after the last active)
|
|
|
|
|
const nextDraft = pipelineRounds.find(
|
|
|
|
|
(r) => r.status === 'ROUND_DRAFT' && r.sortOrder > lastActiveSortOrder
|
|
|
|
|
)
|
|
|
|
|
if (nextDraft) {
|
|
|
|
|
nextActions.push({
|
|
|
|
|
id: `draft-${nextDraft.id}`,
|
|
|
|
|
severity: 'info',
|
|
|
|
|
title: `Configure "${nextDraft.name}"`,
|
|
|
|
|
description: `Next round (${formatRoundType(nextDraft.roundType)}) is in draft`,
|
|
|
|
|
href: `/admin/rounds/${nextDraft.id}`,
|
|
|
|
|
roundId: nextDraft.id,
|
|
|
|
|
roundType: nextDraft.roundType,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 2. Per-active-round actions
|
|
|
|
|
for (const round of activeRounds) {
|
|
|
|
|
// Evaluation rounds: flag unassigned projects
|
|
|
|
|
if (round.roundType === 'EVALUATION' && round.projectStates.total > 0 && round.assignmentCount === 0) {
|
|
|
|
|
nextActions.push({
|
|
|
|
|
id: `unassigned-${round.id}`,
|
|
|
|
|
severity: 'warning',
|
|
|
|
|
title: `${round.projectStates.total} unassigned projects`,
|
|
|
|
|
description: `"${round.name}" has projects without jury assignments`,
|
|
|
|
|
href: `/admin/rounds/${round.id}`,
|
|
|
|
|
roundId: round.id,
|
|
|
|
|
roundType: round.roundType,
|
|
|
|
|
count: round.projectStates.total,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Filtering rounds: flag if filtering not started
|
|
|
|
|
if (round.roundType === 'FILTERING' && round.filteringTotal === 0 && round.projectStates.total > 0) {
|
|
|
|
|
nextActions.push({
|
|
|
|
|
id: `filtering-${round.id}`,
|
|
|
|
|
severity: 'warning',
|
|
|
|
|
title: 'Filtering not started',
|
|
|
|
|
description: `"${round.name}" has ${round.projectStates.total} projects awaiting filtering`,
|
|
|
|
|
href: `/admin/rounds/${round.id}`,
|
|
|
|
|
roundId: round.id,
|
|
|
|
|
roundType: round.roundType,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Deadline warnings
|
|
|
|
|
if (round.windowCloseAt) {
|
|
|
|
|
const days = daysUntil(round.windowCloseAt)
|
|
|
|
|
if (days > 0 && days <= 3) {
|
|
|
|
|
nextActions.push({
|
|
|
|
|
id: `deadline-${round.id}`,
|
|
|
|
|
severity: 'critical',
|
|
|
|
|
title: `${days}d until "${round.name}" closes`,
|
|
|
|
|
description: `Window closes ${round.windowCloseAt.toLocaleDateString()}`,
|
|
|
|
|
href: `/admin/rounds/${round.id}`,
|
|
|
|
|
roundId: round.id,
|
|
|
|
|
roundType: round.roundType,
|
|
|
|
|
})
|
|
|
|
|
} else if (days > 3 && days <= 7) {
|
|
|
|
|
nextActions.push({
|
|
|
|
|
id: `deadline-${round.id}`,
|
|
|
|
|
severity: 'warning',
|
|
|
|
|
title: `${days}d until "${round.name}" closes`,
|
|
|
|
|
description: `Window closes ${round.windowCloseAt.toLocaleDateString()}`,
|
|
|
|
|
href: `/admin/rounds/${round.id}`,
|
|
|
|
|
roundId: round.id,
|
|
|
|
|
roundType: round.roundType,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 3. Pending COIs
|
|
|
|
|
if (pendingCOIs > 0) {
|
|
|
|
|
nextActions.push({
|
|
|
|
|
id: 'pending-cois',
|
|
|
|
|
severity: 'warning',
|
|
|
|
|
title: `${pendingCOIs} COI declarations pending`,
|
|
|
|
|
description: 'Jury members have declared conflicts that need admin review',
|
|
|
|
|
href: '/admin/rounds',
|
|
|
|
|
count: pendingCOIs,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sort by severity
|
|
|
|
|
const severityOrder = { critical: 0, warning: 1, info: 2 }
|
|
|
|
|
nextActions.sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity])
|
|
|
|
|
|
|
|
|
|
// ── Return ──────────────────────────────────────────────────────
|
|
|
|
|
|
2026-02-14 15:26:42 +01:00
|
|
|
return {
|
|
|
|
|
edition,
|
Redesign admin dashboard: pipeline view, round-specific stats, smart actions
Complete rewrite of the admin dashboard replacing the 1056-line monolith with
modular components. Key improvements:
- Competition pipeline: horizontal visualization of all rounds in pipeline order
(by sortOrder, not creation date) with type-specific icons and metrics
- Round-specific stats: stat cards dynamically change based on active round type
(INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION
shows assignments/completion, fallback shows generic project/jury stats)
- Smart actions: context-aware "Action Required" panel that only flags the next
draft round (not all), only flags unassigned projects for EVALUATION rounds,
includes deadline warnings with severity levels (critical/warning/info)
- Active round panel: detailed view with project state bar, type-specific content,
and deadline countdown
- Extracted components: project list, activity feed, category breakdown, skeleton
Backend enriched with 17 parallel queries building rich PipelineRound data
including per-round project states, eval stats, filtering stats, live session
status, and deliberation counts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:12:28 +01:00
|
|
|
// Pipeline
|
|
|
|
|
pipelineRounds,
|
|
|
|
|
activeRoundId,
|
|
|
|
|
// Smart actions
|
|
|
|
|
nextActions,
|
|
|
|
|
// Summary counts
|
2026-02-14 15:26:42 +01:00
|
|
|
projectCount,
|
|
|
|
|
newProjectsThisWeek,
|
|
|
|
|
totalJurors,
|
|
|
|
|
activeJurors,
|
|
|
|
|
evaluationStats,
|
|
|
|
|
totalAssignments,
|
Redesign admin dashboard: pipeline view, round-specific stats, smart actions
Complete rewrite of the admin dashboard replacing the 1056-line monolith with
modular components. Key improvements:
- Competition pipeline: horizontal visualization of all rounds in pipeline order
(by sortOrder, not creation date) with type-specific icons and metrics
- Round-specific stats: stat cards dynamically change based on active round type
(INTAKE shows submissions/docs, FILTERING shows pass/fail/flagged, EVALUATION
shows assignments/completion, fallback shows generic project/jury stats)
- Smart actions: context-aware "Action Required" panel that only flags the next
draft round (not all), only flags unassigned projects for EVALUATION rounds,
includes deadline warnings with severity levels (critical/warning/info)
- Active round panel: detailed view with project state bar, type-specific content,
and deadline countdown
- Extracted components: project list, activity feed, category breakdown, skeleton
Backend enriched with 17 parallel queries building rich PipelineRound data
including per-round project states, eval stats, filtering stats, live session
status, and deliberation counts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:12:28 +01:00
|
|
|
pendingCOIs,
|
|
|
|
|
// Lists
|
2026-02-14 15:26:42 +01:00
|
|
|
latestProjects,
|
|
|
|
|
categoryBreakdown,
|
|
|
|
|
oceanIssueBreakdown,
|
|
|
|
|
recentActivity,
|
|
|
|
|
}
|
|
|
|
|
}),
|
2026-02-18 12:43:28 +01:00
|
|
|
|
|
|
|
|
getRecentEvaluations: adminProcedure
|
|
|
|
|
.input(z.object({ editionId: z.string(), limit: z.number().int().min(1).max(50).optional() }))
|
|
|
|
|
.query(async ({ ctx, input }) => {
|
|
|
|
|
const take = input.limit ?? 10
|
|
|
|
|
|
|
|
|
|
const evaluations = await ctx.prisma.evaluation.findMany({
|
|
|
|
|
where: {
|
|
|
|
|
status: 'SUBMITTED',
|
|
|
|
|
assignment: {
|
|
|
|
|
round: { competition: { programId: input.editionId } },
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
orderBy: { submittedAt: 'desc' },
|
|
|
|
|
take,
|
|
|
|
|
select: {
|
|
|
|
|
id: true,
|
|
|
|
|
globalScore: true,
|
|
|
|
|
binaryDecision: true,
|
|
|
|
|
submittedAt: true,
|
|
|
|
|
feedbackText: true,
|
|
|
|
|
assignment: {
|
|
|
|
|
select: {
|
|
|
|
|
project: { select: { id: true, title: true } },
|
|
|
|
|
round: { select: { id: true, name: true } },
|
|
|
|
|
user: { select: { id: true, name: true, email: true } },
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return evaluations
|
|
|
|
|
}),
|
2026-02-14 15:26:42 +01:00
|
|
|
})
|