Admin platform audit: fix bugs, harden backend, add auto-refresh, clean dead code
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m23s
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m23s
Phase 1 — Critical bugs: - Fix deliberation participant selection (wire jury group query) - Fix reports "By Round" tab (inline content instead of 404 route) - Fix messages "Sent History" (add message.sent procedure, wire tab) - Add missing fields to competition award form (criteriaText, maxRankedPicks) - Wire LiveControlPanel buttons (cursor, voting, scores) - Fix ResultLockControls empty snapshot (fetch actual data before lock) - Fix SubmissionWindowManager losing fields on edit Phase 2 — Backend fixes: - Remove write-in-query from specialAward.get - Fix award eligibility job overwriting manual shortlist overrides - Fix filtering startJob deleting all prior results (defer cleanup to post-success) - Tighten access control: protectedProcedure → adminProcedure on 8 procedures - Add audit logging to deliberation mutations - Add FINALIST/SEMIFINALIST delete guard on project.delete/bulkDelete Phase 3 — Auto-refresh: - Add refetchInterval to 15+ admin pages/components (10s–30s) - Fix AI job polling: derive speed from job status for all viewers Phase 4 — Dead code cleanup: - Delete unused command-palette, pdf-report, admin-page-transition - Remove dead subItems sidebar code, unused GripVertical import - Replace redundant isGenerating state with mutation.isPending - Add Role column to jury members table - Remove misleading manual mentor assignment stub Phase 5 — UX improvements: - Fix rounds page single-competition assumption (add selector) - Remove raw UUID fallback in deliberation config - Fix programs page "Stage" → "Round" terminology Phase 6 — Backend hardening: - Complete logAudit calls (add prisma, ipAddress, userAgent) - Batch analytics queries (fix N+1 in getCrossRoundComparison, getYearOverYear) - Batch user.bulkCreate writes (assignments, jury memberships, intents) - Remove any casts from deliberation service (typed PrismaClient + TransactionClient) - Fix stale DeliberationStatus enum values blocking build 40 files changed, 1010 insertions(+), 612 deletions(-) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -35,7 +35,6 @@ import {
|
||||
Pencil,
|
||||
Trash2,
|
||||
FileText,
|
||||
GripVertical,
|
||||
FileCheck,
|
||||
FileQuestion,
|
||||
} from 'lucide-react'
|
||||
|
||||
@@ -95,6 +95,7 @@ export function FilteringDashboard({ competitionId, roundId }: FilteringDashboar
|
||||
const [page, setPage] = useState(1)
|
||||
const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set())
|
||||
const [pollingJobId, setPollingJobId] = useState<string | null>(null)
|
||||
const [jobRunning, setJobRunning] = useState(false)
|
||||
const [overrideDialogOpen, setOverrideDialogOpen] = useState(false)
|
||||
const [overrideTarget, setOverrideTarget] = useState<{ id: string; name: string } | null>(null)
|
||||
const [overrideOutcome, setOverrideOutcome] = useState<'PASSED' | 'FILTERED_OUT' | 'FLAGGED'>('PASSED')
|
||||
@@ -127,14 +128,19 @@ export function FilteringDashboard({ competitionId, roundId }: FilteringDashboar
|
||||
onError: (err) => toast.error(err.message),
|
||||
})
|
||||
|
||||
// Dynamic refetch: all viewers get fast polling when a job is running (not just the one who started it)
|
||||
const { data: latestJob } = trpc.filtering.getLatestJob.useQuery(
|
||||
{ roundId },
|
||||
{ refetchInterval: pollingJobId ? 3_000 : 15_000 },
|
||||
{ refetchInterval: jobRunning ? 3_000 : 15_000 },
|
||||
)
|
||||
|
||||
// Dynamic refetch: 3s during running job, 15s otherwise
|
||||
const isRunning = !!pollingJobId || latestJob?.status === 'RUNNING'
|
||||
|
||||
// Sync jobRunning so fast polling kicks in for ALL viewers, not just the job starter
|
||||
useEffect(() => {
|
||||
setJobRunning(isRunning)
|
||||
}, [isRunning])
|
||||
|
||||
const { data: stats, isLoading: statsLoading } = trpc.filtering.getResultStats.useQuery(
|
||||
{ roundId },
|
||||
{ refetchInterval: isRunning ? 3_000 : 15_000 },
|
||||
|
||||
@@ -188,10 +188,10 @@ export function SubmissionWindowManager({ competitionId, roundId }: SubmissionWi
|
||||
roundNumber: window.roundNumber,
|
||||
windowOpenAt: window.windowOpenAt ? new Date(window.windowOpenAt).toISOString().slice(0, 16) : '',
|
||||
windowCloseAt: window.windowCloseAt ? new Date(window.windowCloseAt).toISOString().slice(0, 16) : '',
|
||||
deadlinePolicy: 'HARD_DEADLINE', // Not available in query, use default
|
||||
graceHours: 0, // Not available in query, use default
|
||||
lockOnClose: true, // Not available in query, use default
|
||||
sortOrder: 1, // Not available in query, use default
|
||||
deadlinePolicy: window.deadlinePolicy ?? 'HARD_DEADLINE',
|
||||
graceHours: window.graceHours ?? 0,
|
||||
lockOnClose: window.lockOnClose ?? true,
|
||||
sortOrder: window.sortOrder ?? 1,
|
||||
})
|
||||
setEditingWindow(window.id)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user