- Add getSemiFinalistStats query with per-category/per-award breakdown
- Add sendAccountReminders mutation with invite token generation and dedup
- Add SemiFinalistTracker dashboard widget with progress bars and remind buttons
- Add ACCOUNT_REMINDER email template
- Extend project search to match team member name/email (7 locations)
- Fix Passed count deduplication: count distinct projects, not round-state rows
- Fix role switcher: visible pills above user section, auto-refresh session on mount
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add attachProjectLogoUrls utility mirroring avatar URL pattern. Pipe
project.list and analytics.getAllProjects through logo URL resolver so
ProjectLogo components receive presigned URLs. Add logos to observer
projects table and mobile cards.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Custom body support for advancement/rejection notification emails, evaluation
config toggle fix, user actions improvements, round finalization with reorder
support, project detail page enhancements, award pool duplicate prevention.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add admin settings: learning_hub_external, learning_hub_external_url, support_email
- Jury/Mentor nav respects external Learning Hub URL (opens in new tab)
- RoleNav supports external nav items with ExternalLink icon
- Applicant header shows Help button with configurable support email
- Settings update mutation now upserts (creates on first use)
- Shared inferSettingCategory for consistent category assignment
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Award "Notify Pool" dialog now uses EmailPreviewDialog with live preview
- Button shows eligible project count: "Notify Pool (38)"
- Finalization tab email section has "Preview" buttons for both
advancement and rejection messages
- EmailPreviewDialog supports previewOnly mode (close button, no send)
- Backend: previewAwardSelectionEmail, previewFinalizationAdvancementEmail,
previewFinalizationRejectionEmail queries
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- processRoundClose now applies reordersJson drag-reorder overrides
when building the evaluation pass set (was ignoring admin reorders)
- Finalization tab groups proposed outcomes by category (Startup/Concept)
with per-group pass/reject/total counts
- Added category filter dropdown alongside the existing outcome filter
- Removed legacy "Advance Top N" button and dialog from ranking page
(replaced by the finalization workflow)
- Fix project edit status defaultValue showing empty placeholder
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- processRoundClose EVALUATION uses ranking scores + advanceMode config
(threshold vs count) to auto-set proposedOutcome instead of defaulting all to PASSED
- Advancement emails generate invite tokens for passwordless users with
"Create Your Account" CTA; rejection emails have no link
- Finalization UI shows account stats (invite vs dashboard link counts)
- Fixed getFinalizationSummary ranking query (was using non-existent rankingsJson)
- New award pool notification system: getAwardSelectionNotificationTemplate email,
notifyEligibleProjects mutation with invite token generation,
"Notify Pool" button on award detail page with custom message dialog
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Always display yes/no count format (e.g. "0/2 Yes") instead of
generic "2 jurors" when no advance votes exist
- Color coding: 2/2 Yes = green, 1/2 Yes = amber, 0/2 Yes = red
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The display was sorted by compositeScore (which factors in pass rate and
z-score normalization) but the cutoff line and displayed values use
avgGlobalScore. This caused projects with high averages but low pass
rates (e.g. 1/2 Yes) to appear below the cutoff even when their average
exceeded the threshold.
Now sorts by avgGlobalScore (the visible metric) with compositeScore as
tiebreaker. Also adds a green left border to advancing projects for
clearer threshold highlighting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Sort deduped ranking entries by compositeScore descending during
localOrder init — ensures correct display order for both formula
and old AI snapshots
- Fix threshold cutoff: scan forward to find first non-qualifying
project instead of backward scan that left non-qualifying projects
above the line
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add scoreWeight and passRateWeight (0-10) to evaluation config for
configurable composite score formula. When ranking criteria text is
empty, triggerAutoRank uses pure formula ranking (no LLM calls).
When criteria text is present, AI-assisted ranking runs as before.
- Add FORMULA to RankingMode enum with migration
- Extract fetchCategoryProjects helper, add formulaRank service
- Update computeCompositeScore to accept configurable weights
- Add score/pass-rate weight sliders to ranking dashboard UI
- Mode-aware button labels (Calculator/formula vs Sparkles/AI)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Create snapshot with status RUNNING before AI call starts
- Update to COMPLETED/FAILED when done
- Dashboard derives rankingInProgress from server snapshot status
- All admins see the spinner, not just the one who triggered it
- Poll snapshots every 3s so progress updates appear quickly
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Sort all ranked projects by compositeScore descending so highest-rated
projects always appear first (instead of relying on AI's inconsistent rank order)
- Deduplicate AI ranking response (AI sometimes returns same project multiple times)
- Deduplicate ranking entries and reorder IDs on dashboard load as defensive measure
- Show advancement cutoff line only once (precompute last advancing index)
- Override badge only shown when admin has actually drag-reordered (not on fresh rankings)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Apply saved reordersJson when initializing the dashboard so any admin
sees the latest drag-reorder state, not just the original AI order.
The latest reorder event per category is used as the initial localOrder.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- AI ranking now includes ALL projects (never filters/excludes any)
- Updated system prompt: filter criteria inform priority, not exclusion
- Dynamic maxTokens scaling for large project pools (80 tokens/project)
- Fallback: projects AI omits are appended sorted by composite score
- Override badge uses snapshotOrder state (synced with localOrder in same
useEffect) instead of rankingMap.originalIndex to prevent stale-render
mismatch where all items incorrectly showed as overridden
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Header shows "Score >= X advance" instead of "Top N" in threshold mode
- Cutoff line placed after last project meeting threshold, not at fixed count
- Projects advancing determined by avg score vs threshold, not position
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Backfilled 166 evaluations' binaryDecision from criterionScoresJson on production DB
- Fixed roundEvaluationScores and ai-ranking to look in EvaluationForm.criteriaJson
instead of round.configJson for the boolean "Move to the Next Stage?" criterion
- Added advanceMode (count/threshold) toggle to round config Advancement Targets
- Added "Assign to Jurors" button on Unassigned Projects section and Projects tab bulk bar
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add criteriaWeights to EvaluationConfig for per-criterion weight assignment (0-10)
- Rewrite ai-ranking service: fetch eval form criteria, compute per-criterion averages,
z-score normalize juror scores to correct grading bias, send weighted criteria to AI
- Update AI prompts with criteria_definitions and per-project criteria_scores
- compositeScore uses weighted criteria when configured, falls back to globalScore
- Add collapsible ranking config section to dashboard (criteria text + weight sliders)
- Move rankingCriteria textarea from eval config tab to ranking dashboard
- Store criteriaWeights in ranking snapshot parsedRulesJson for audit
- Enhance projectScores CSV export with per-criterion averages, category, country
- Add Export CSV button to ranking dashboard header
- Add threshold-based advancement mode (decimal score threshold, e.g. 6.5)
alongside existing top-N mode in advance dialog
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add adminEditEvaluation mutation and getJurorEvaluations query
- Create shared EvaluationEditSheet component with inline feedback editing
- Add Evaluations tab to member detail page (grouped by round)
- Make jury group member names clickable (link to member detail)
- Replace inline EvaluationDetailSheet on project page with shared component
- Fix project status transition validation (skip when status unchanged)
- Fix frontend to not send status when unchanged on project edit
- Ranking dashboard improvements and boolean decision converter fixes
- Backfill script updates for binary decisions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add nationality/institution fields to User model with migration
- Applicant onboarding wizard (name, photo, nationality, country, institution, bio, project logo, preferences)
- Project logo upload from applicant context with team membership verification
- APPLICANT redirects in set-password, onboarding, and auth layout
- Mask evaluation round names as "Evaluation Round 1/2/..." for applicants
- Extend inviteTeamMember with nationality/country/institution/sendInvite fields
- Admin getApplicants query with search/filter/pagination
- Admin bulkInviteApplicants mutation with token generation and emails
- Applicants tab on Members page with bulk select and floating invite bar
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- ProjectStatesTable local search now covers country, institution, competitionCategory, geographicZone
- project-pool.ts DB search extended to institution, country, geographicZone, team member names
- AwardShortlist eligibility table gains a search input filtering by title, team, country, institution, category
- IndividualAssignmentsTable project filter extended to include country and institution
- Add "Generate AI Tags" dropdown item per row in ProjectStatesTable using tag.tagProject mutation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- IndividualAssignmentsTable: add View Project (new tab) as first dropdown item
- AwardShortlist: make project title a clickable link opening in new tab
- ProjectStatesTable: change View Project from same-tab Link to new-tab anchor
- Round page: Awards tab now only shown when roundAwards.length > 0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Chart: fixed bars not rendering by using explicit h-[160px] + min-h-0 on
the bar container so percentage-based heights resolve correctly.
Script: one-off backfill copies the custom "Move to the Next Stage?" boolean
criterion value into binaryDecision for evaluations where it's null.
Run: npx tsx scripts/backfill-binary-decision.ts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds getProjectStates query to build a projectInfoMap lookup. Each row now
shows the project title, team name, and country. Also renames "Pass" label
to "Yes" to match the binary yes/no vote semantics.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The backend reads rankingCriteria from configJson but there was no UI field
to set it. Adds a Textarea and autoRankEnabled switch to the AI Features card
in the evaluation round config.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add pendingReorderCount ref + onMutate/onSettled to saveReorderMutation (DASH-07)
- Add advanceMutation (trpc.round.advanceProjects) with getProjectStates invalidation
- Add batchRejectMutation (trpc.roundEngine.batchTransition) using .length per MEMORY.md
- Add handleAdvance: advances top N per category, optionally batch-rejects the rest
- Add Advance Top N button in header (disabled when saveReorderMutation.isPending)
- Add Dialog with per-category N inputs, batch-reject checkbox, and count preview
- Import Dialog, Input, Label, Trophy from shadcn/lucide
- Update listByStage query to include evaluation form criteriaJson and criterionScoresJson
- Add Advance column to individual assignments table showing YES/NO badge per submitted evaluation
- Create AdvancementSummaryCard component showing yes/no/pending vote counts with stacked bar
- Wire AdvancementSummaryCard into the EVALUATION round overview tab
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add getMyProgress juryProcedure query to evaluationRouter: fetches all
assignments for the current juror in a round, tallies completed/total,
advance yes/no counts, per-project numeric scores and averages
- Create JurorProgressDashboard client component with progress bar, advance
badge summary, and collapsible per-submission score table
- Wire dashboard into jury round page, gated by configJson.showJurorProgressDashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Jury evaluate page: add prominent advance criterion block (h-14, brand-blue border) before boolean block, fix type cast to include 'advance', add advance to required-field validation
- evaluation-form.tsx: add 'advance' to CriterionType, schema, default values, progress tracking, rendering via new AdvanceCriterionField component with prominent styling
- Admin project detail: treat advance same as boolean in EvaluationDetailSheet criterion score display
- Observer project detail: treat advance same as boolean in evaluation criterion score display
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a new 'advance' criterion type representing "should this project advance to the next round?". Only one advance criterion is allowed per form (button disabled once added). No weight, no condition fields, always required. Also updates the upsertForm Zod schema to accept the new type.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add roles UserRole[] to User model with migration + backfill from existing role column
- Update auth JWT/session to propagate roles array with [role] fallback for stale tokens
- Update tRPC hasRole() middleware and add userHasRole() helper for inline role checks
- Update ~15 router inline checks and ~13 DB queries to use roles array
- Add updateRoles admin mutation with SUPER_ADMIN guard and priority-based primary role
- Add role switcher UI in admin sidebar and role-nav for multi-role users
- Remove redundant stats cards from round detail, add window dates to header banner
- Merge Members section into JuryProgressTable with inline cap editor and remove buttons
- Reorder round detail assignments tab: Progress > Score Dist > Assignments > Coverage > Jury Group
- Make score distribution fill full vertical height, reassignment history always open
- Add per-juror progress bars to admin dashboard ActiveRoundPanel for EVALUATION rounds
- Fix evaluation submit bug: use isSubmitting state instead of startMutation.isPending
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend: getProjectRoundStates now includes assignment counts and submitted
evaluation counts per project. Frontend: new Reviews column shows X/Y
(submitted/total) with green highlight when all reviews are complete.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Initialize slider values to midpoint so visual matches stored value
(root cause: sliders appeared filled but criteriaValues was undefined)
- Use mutateAsync for submit to properly await and prevent double-clicks
- Add startMutation.isPending to submit button disabled state
- Add error toast in evaluation-form.tsx catch block (was silent)
- Show "Ready to submit" badge and "Review & Submit" button for drafts
on juror dashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add mail/transfer/reshuffle/redistribute icons to each juror row in Members card
- New redistributeJurorAssignments procedure: reassign all pending projects without dropping juror from group
- New DROPOUT_REASSIGNED email template with project names, deadline, and dropped juror context
- Update reassignDroppedJuror to send per-juror DROPOUT_REASSIGNED emails instead of generic BATCH_ASSIGNED
- Transfer dialog now shows all candidates with "Already assigned" / "At cap" labels instead of hiding them
- SQL script for prod DB insertion of new notification setting without seeding
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add COI_REASSIGNED and MANUAL_REASSIGNED notification types with distinct
email templates, icons, and priorities
- COI declaration dialog now shows a confirmation step warning that the
project will be reassigned before submitting
- reassignAfterCOI now checks historical assignments (all rounds, audit logs)
to never assign the same project to a juror twice, and prefers jurors with
incomplete evaluations over those who have finished all their work
- Admin transfer (transferAssignments) sends per-juror MANUAL_REASSIGNED
notifications with actual project names instead of generic batch emails
- docker-entrypoint syncs notification settings on every deploy via upsert
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Rewrite ctaButton to use td-background pattern (works in all clients
including Outlook, Gmail, Yahoo, Apple Mail) instead of VML/conditional
comments that broke link clicking in Outlook desktop
- Add plaintext fallback URL below every CTA button so users always have
a working link even if the button fails
- Add getBaseUrl() and ensureAbsoluteUrl() helpers in email.ts to
guarantee all email links are absolute https:// URLs
- Apply ensureAbsoluteUrl safety net in sendStyledNotificationEmail and
sendNotificationEmail so relative paths can never reach email templates
- Standardize all NEXTAUTH_URL fallbacks to https://portal.monaco-opc.com
(was inconsistently http://localhost:3000 or https://monaco-opc.com)
- Fix legacy notification.ts: wrong argument order in
sendJuryInvitationEmail (URL was passed as name parameter)
- Fix legacy notification.ts: missing NEXTAUTH_URL fallback for
evaluation reminder URL construction
- Change tooltip styling from red bg to white bg with black text
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add getTransferCandidates/transferAssignments procedures for targeted
assignment moves between jurors with TOCTOU guards and audit logging
- Add getOverCapPreview/redistributeOverCap for auto-redistributing
assignments when a juror's cap is lowered below their current load
- Add TransferAssignmentsDialog (2-step: select projects, pick destinations)
- Extend InlineMemberCap with over-cap detection and redistribute banner
- Extend getReassignmentHistory to show ASSIGNMENT_TRANSFER and CAP_REDISTRIBUTE events
- Learning hub: replace ResourceType/CohortLevel enums with accessJson JSONB,
add coverImageKey, resource detail pages for jury/mentor, shared renderer
- Migration: 20260221200000_learning_hub_overhaul
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Anthropic API:
- Add @anthropic-ai/sdk with adapter wrapping OpenAI-shaped interface
- Support Claude models (opus, sonnet, haiku) with extended thinking
- Auto-reset model on provider switch, JSON retry logic
- Add Claude model pricing to ai-usage tracker
- Update AI settings form with Anthropic provider option
- Add provider field to AIUsageLog for cross-provider cost tracking
Locale Settings Removal:
- Strip Localization tab from admin settings (mobile + desktop)
- Remove i18n settings from router and feature flags
- Remove LOCALIZATION from SettingCategory enum
- Keep franc document language detection intact
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Rewrite diversity metrics: horizontal bar charts for ocean issues and
geographic distribution (replaces unreadable vertical/donut charts)
- Rewrite juror score heatmap: expandable table with score distribution
- Rewrite juror consistency: horizontal bar visual with juror names
- Merge filtering tabs into single screening view with per-project
AI reasoning and expandable rows
- Add project preview dialog for juror performance table
- Fix status breakdown for evaluation rounds (Fully/Partially/Not Reviewed)
- Show active round name instead of count on observer dashboard
- Move Global tab to last position, default to first round-specific tab
- Add 4-card stats layout for evaluation with reviews/project ratio
- Fix oceanIssue field (singular) and remove non-existent aiSummary
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Refactor the observer reports page from a static 3-tab layout to a
dynamic tab system that adapts to each round type (INTAKE, FILTERING,
EVALUATION, SUBMISSION, MENTORING, LIVE_FINAL, DELIBERATION). Adds a
persistent Global tab for edition-wide analytics, juror score heatmap,
expandable juror assignment rows, filtering screening bar, and
deliberation results with tie detection.
- Add 5 observer proxy procedures to analytics router
- Create JurorScoreHeatmap, ExpandableJurorTable, FilteringScreeningBar
- Create 8 round-type tab components + GlobalAnalyticsTab
- Reduce reports page from 914 to ~190 lines (thin dispatcher)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>