- Add Team tab to observer project detail (configurable via admin settings)
- Move applicant jury feedback visibility from per-round config to admin settings
- Add per-round-type controls: evaluation, live final, deliberation
- Support anonymous LiveVote and DeliberationVote display for applicants
- Add fine-grained toggles: scores, criteria, written feedback, hide from rejected
- Backwards compatible: falls back to old per-round config if admin settings not set
- New admin settings section under Analytics tab with all visibility controls
- Seed new SystemSettings keys for observer/applicant visibility
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add updateTeamMemberRole mutation for admins to change team member roles
- Allow any team member (not just lead) to change project logo
- Add visible "Add logo"/"Change" label under logo for discoverability
- Pre-check email existence before sending magic link (show error)
- Add "forgot which email" contact link on login page
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Messages were sent in a tight for-loop with no throttling. Now uses
sendBatchNotifications (10/batch, 150ms per email, 500ms between
batches) and fires in the background so the admin gets instant response.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Award-specific rounds (e.g. Spotlight on Africa) were mixed into the
main pipeline as a flat list, making them look like sequential steps
after Deliberation. Now they render in their own amber-tinted card
sections below the main pipeline, each with a header showing award
name, pool size, eligibility mode, and status.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix impersonation by bypassing useSession().update() loading gate with direct session POST
- Fix dashboard account counter defaulting to latest round with PASSED projects
- Add clickToEnlarge lightbox for project logos on admin detail page
- Remove submission eligibility config (all passed projects must upload)
- Suppress CredentialsSignin auth errors in production (minified name check)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Status counts now show each project's latest round state only
(no more inflated counts from projects passing multiple rounds)
- Add pagination controls at top of projects, members, and observer lists
- Add sortable column headers to admin projects table (title, category,
program, assignments, status) and members table (name, role, status,
last login)
- Backend: add sortBy/sortDir params to project.list and user.list
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously counted distinct projects per state across ALL rounds,
inflating counts (e.g., 215 Passed when many were later rejected).
Now picks each project's latest round state (highest sortOrder) to
determine its current status.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix session auto-refresh causing re-render cascade by using useRef
instead of useState and delaying the refresh by 3s
- Make project logo clickable on dashboard and team page for team leads
with hover pencil overlay and ProjectLogoUpload dialog
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Sign Out button during impersonation now returns to admin instead of
destroying the session (fixes multi-click logout issue)
- Applicant nav now respects learning_hub_external setting like jury/mentor
- Track Learning Hub nav clicks via audit log (LEARNING_HUB_CLICK action)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace Semi-Finalist Tracker with Round User Tracker on dashboard
- New getRoundUserStats query: round-aware account activation stats
- Round selector dropdown to view any round's passed projects
- sendAccountReminders now accepts optional roundId for scoped reminders
- Fix: signIn callback now sets status=ACTIVE for INVITED users on login
- DB fix: 5 users who logged in via magic link but stayed INVITED → ACTIVE
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Password reset:
- /forgot-password page: enter email, receive reset link via email
- /reset-password?token=xxx page: set new password with validation
- user.requestPasswordReset: generates token, sends styled email
- user.resetPassword: validates token, hashes new password
- Does NOT trigger re-onboarding — only resets the password
- 30-minute token expiry, cleared after use
- Added passwordResetToken/passwordResetExpiresAt to User model
Member detail page fixes:
- Hide "Expertise & Capacity" card for applicants/audience roles
- Show country names with flag emojis instead of raw ISO codes
- Login "Forgot password?" now links to /forgot-password page
Project detail page:
- Team member details show full country names with flags
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Member detail page (/admin/members/[id]) now shows:
- Profile details card (nationality, country, institution, bio)
- Team memberships / projects with links to project pages
- Jury groups with role (Chair/Member/Observer)
- All roles including Applicant, Award Master, Audience in role selector
- Project detail page team members now show:
- Nationality, institution, country inline
- Names are clickable links to member profile pages
- Members list: names are clickable links to profile pages (all tabs)
- Applicants tab: added nationality and institution columns
- Backend: user.get includes teamMemberships and juryGroupMemberships
- Backend: project.getFullDetail includes nationality/country/institution
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- MinIO: use separate public client for presigned URLs so AWS V4 signature
matches the browser's Host header (fixes SignatureDoesNotMatch on all uploads)
- Consolidate applicant/partner uploads to mopc-files bucket (removes
non-existent mopc-submissions and mopc-partners buckets)
- Auth: allow magic links for any non-SUSPENDED user (was ACTIVE-only,
blocking first-time CSV-seeded applicants)
- Auth: accept invite tokens for any non-SUSPENDED user (was INVITED-only)
- Ensure all 14 invite token locations set status to INVITED
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add error logging to silent catch blocks in avatar/logo URL generation,
show user avatar on admin member detail page, and surface specific error
messages for upload failures (CORS/network issues) instead of generic errors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add vertical padding to the scrollable pipeline container so
the ring-2 highlight on selected rounds isn't clipped.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace router.push() with window.location.href for both
start and end impersonation to ensure the updated JWT cookie
is sent with the new request. Client-side routing can race
with cookie propagation, causing the server to see the old
session and redirect back to admin.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
getConfig now throws FORBIDDEN when round is not ROUND_ACTIVE,
preventing the form from loading entirely. Also blocks draft
saving when round is inactive. Defense-in-depth: submit already
rejected inactive rounds, this adds the frontend gate.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add withErrorAudit middleware tracking FORBIDDEN/UNAUTHORIZED/NOT_FOUND per user
- Fix impersonation attribution: log real admin ID, prefix IMPERSONATED_ on actions
- Add ACCOUNT_LOCKED audit events on login lockout (distinct from LOGIN_FAILED)
- Audit export of assignments and audit logs (meta-audit gap)
- Update audit page UI with new security event types and colors
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace single FILE_DOWNLOADED action with three granular actions:
- FILE_VIEWED: inline preview loaded in the UI
- FILE_OPENED: file opened in a new browser tab
- FILE_DOWNLOADED: explicit download button clicked
Add 'purpose' field to getDownloadUrl input (preview/open/download).
All client callers updated to pass the appropriate purpose.
Audit page updated with new filter options and color mappings.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
getDownloadUrl was logging FILE_DOWNLOADED on every call including
inline previews and thumbnail loads. Now only logs when forDownload
is true (explicit download button click), massively reducing noise.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Applicants could bypass onboarding and land directly on the dashboard.
Added onboardingCompletedAt check + redirect to /onboarding in both
the applicant and observer layouts (jury/mentor already had this gate).
Also removed premature status ACTIVE on magic-link first login — now
only completeOnboarding sets ACTIVE.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Applicant saveFileMetadata and deleteFile mutations now log
APPLICANT_UPLOAD_FILE and APPLICANT_DELETE_FILE to the audit trail,
matching the admin file router's existing audit coverage.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 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>
Fix round-specific document uploads (submittedAt no longer blocks uploads),
add view/download buttons for existing files, enforce active-round-only for
uploads/deletes. Harden auth layout and set-password page. Filter applicant
portal rounds by award track membership.
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 notifiedAt field to AwardEligibility. notifyEligibleProjects now
skips already-notified entries and stamps notifiedAt after sending,
so re-clicking "Notify Pool" only emails newly added projects.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- getNavFlags/getMyEvaluations: return empty when project has no round
states instead of dropping the filter (prevented phantom eval rounds)
- getUpcomingDeadlines: detect isInAwardTrack from ProjectRoundState
join instead of pre-filtered deadline rounds
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Projects in SEPARATE_POOL awards now only see their award rounds (not main
pool rounds) across all applicant queries: openRounds, deadlines, document
completeness, nav flags, and evaluations.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The email was implying projects had won the award. Updated banner, subject,
and body copy to clarify they are being considered, not awarded.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add drag-and-drop round reordering on award detail Rounds tab (dnd-kit)
- Replace "Open Voting" with "Assign to First Round" for SEPARATE_POOL awards
- Add reorderAwardRounds mutation (two-phase transaction for unique constraint)
- Add assignToFirstRound mutation (re-runnable, moves/creates ProjectRoundState)
- Extend applicant timeline to show award-specific rounds for SEPARATE_POOL projects
- Hide irrelevant main competition rounds when project is in award track
- Prefix award round labels with award name in timeline
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>
The migration adding gracePeriodEndsAt, finalizedAt, finalizedBy to Round
and proposedOutcome to ProjectRoundState was never committed, causing
production to fail with "column does not exist" errors.
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>
Submission, Intake, and Mentoring rounds don't use score-based
advancement (Fixed Count / Score Threshold). The section is now
only shown for Evaluation and Filtering rounds.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The outer Tooltip on the status badge was overlaying the DropdownMenu
content, hiding "Reopen Round". Now the tooltip is forced closed
whenever the dropdown is open.
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>