Commit Graph

56 Commits

Author SHA1 Message Date
13f125af28 feat: error audit middleware, impersonation attribution, account lockout logging
All checks were successful
Build and Push Docker Image / build (push) Successful in 10m13s
- 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>
2026-03-04 18:28:56 +01:00
6c52e519e5 feat: impersonation system, semi-finalist detail page, tRPC resilience
- Add super-admin impersonation: "Login As" from user list, red banner
  with "Return to Admin", audit logged start/end, nested impersonation
  blocked, onboarding gate skipped during impersonation
- Fix semi-finalist stats: check latest terminal state (not any PASSED),
  use passwordHash OR status=ACTIVE for activation check
- Add /admin/semi-finalists detail page with search, category/status filters
- Add account_reminder_days setting to notifications tab
- Add tRPC resilience: retry on 503/HTML responses, custom fetch detects
  nginx error pages, exponential backoff (2s/4s/8s)
- Reduce dashboard polling intervals (60s stats, 30s activity, 120s semi)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 17:55:44 +01:00
b1a994a9d6 fix: enforce onboarding gate for applicants and observers
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m37s
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>
2026-03-04 17:00:19 +01:00
43e21c6c6e feat: semi-finalist tracker dashboard, account reminders, search + UX fixes
- 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>
2026-03-04 15:41:03 +01:00
af03c12ae5 feat: per-round advancement selection, email preview, Docker/auth fixes
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m42s
- Bulk notification dialog: per-round checkboxes (default none selected),
  selected count badge, "Preview Email" button with rendered iframe
- Backend: roundIds filter on sendBulkPassedNotifications, new
  previewAdvancementEmail query
- Docker: add external MinIO network so app container can reach MinIO
- File router: try/catch on getPresignedUrl with descriptive error
- Auth: custom NextAuth logger suppresses CredentialsSignin stack traces

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 14:31:01 +01:00
a39e27f6ff fix: applicant portal — document uploads, round filtering, auth hardening
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>
2026-03-04 13:29:39 +01:00
f24bea3df2 feat: extend notification system with batch sender, bulk dialog, and logging
Add NotificationLog schema extensions (nullable userId, email, roundId,
projectId, batchId fields), batch notification sender service, and bulk
notification dialog UI. Include utility scripts for debugging and seeding.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 13:29:06 +01:00
84d90e1978 fix: soften award notification email tone from "selected" to "under consideration"
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m32s
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>
2026-03-04 00:04:28 +01:00
cfee3bc8a9 feat: round finalization with ranking-based outcomes + award pool notifications
All checks were successful
Build and Push Docker Image / build (push) Successful in 10m0s
- 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>
2026-03-03 19:14:41 +01:00
f3fd9eebee Multi-role members, round detail UI overhaul, dashboard jury progress, and submit bug fix
Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
- 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>
2026-02-24 17:44:55 +01:00
95d51e7de3 Add juror quick actions to Members section, redistribute button, dropout emails, and transfer duplicate detection
Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
- 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>
2026-02-23 16:08:46 +01:00
49e9405e01 Add COI/manual reassignment emails, confirmation dialog, and smart juror selection
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m14s
- 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>
2026-02-23 14:56:30 +01:00
c1b3a6ade3 Fix email links broken in Outlook and standardize all email URLs
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m33s
- 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>
2026-02-23 14:27:58 +01:00
f26ee3f076 Admin dashboard & round management UX overhaul
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m43s
- Extract round detail monolith (2900→600 lines) into 13 standalone components
- Add shared round/status config (round-config.ts) replacing 4 local copies
- Delete 12 legacy competition-scoped pages, merge project pool into projects page
- Add round-type-specific dashboard stat panels (submission, mentoring, live final, deliberation, summary)
- Add contextual header quick actions based on active round type
- Improve pipeline visualization: progress bars, checkmarks, chevron connectors, overflow fix
- Add config tab completion dots (green/amber/red) and inline validation warnings
- Enhance juries page with round assignments, member avatars, and cap mode badges
- Add context-aware project list (recent submissions vs active evaluations)
- Move competition settings into Manage Editions page

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 17:14:00 +01:00
f42b452899 Add Anthropic API integration, remove locale settings UI
All checks were successful
Build and Push Docker Image / build (push) Successful in 13m15s
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>
2026-02-21 17:26:59 +01:00
Matt
baca483fcb Comprehensive round system audit: fix 27 logic bugs, add manual project/assignment features, improve UI/UX
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m23s
## Critical Logic Fixes (Tier 1)
- Fix requiredReviews config key mismatch (always defaulted to 3)
- Fix double-email + stageName/roundName metadata mismatch in notifications
- Fix snake_case config reads in peer review (peerReviewEnabled was always blocked)
- Add server-side COI check to evaluation submit (was client-only)
- Fix hard-coded feedbackText.min(10) — now uses config values
- Fix binaryDecision corruption in non-binary scoring modes
- Fix advanceProjects: add competition/sort-order/status validations, move autoPass into tx
- Fix removeFromRound: now cleans up orphaned Assignment records
- Fix 3-day reminder sending wrong email template (was using 24h template)

## High-Priority Logic Fixes (Tier 2)
- Add project state transition whitelist (prevent invalid transitions like REJECTED→PASSED)
- Scope AI assignment job to jury group members (was querying all JURY_MEMBERs)
- Add COI awareness to AI assignment generation
- Enforce requireAllCriteriaScored server-side
- Fix expireIntentsForRound nested transaction (now uses caller's tx)
- Implement notifyOnEntry for advancement path
- Implement notifyOnAdvance (was dead config)
- Fix checkRequirementsAndTransition for SubmissionFileRequirement model

## New Features (Tier 3)
- Add Project to Round: dialog with "Create New" and "From Pool" tabs
- Assignment "By Project" mode: select project → assign multiple jurors
- Backend: project.createAndAssignToRound procedure

## UI/UX Improvements (Tier 4+5)
- Add AlertDialog confirmation to header status dropdown
- Replace native confirm() with AlertDialog in assignments table
- Jury stats card now display-only with "Change" link
- Assignments tab restructured into logical card groups
- Inline-editable round name in header
- Back button shows destination label
- Readiness checklist: green check instead of strikethrough
- Gate assignments tab when no jury group assigned
- Relative time on window stats card
- Toast feedback on date saves
- Disable advance button when no target round
- COI section shows placeholder when empty
- Round position shown as "Round X of Y"
- InlineMemberCap edit icon always visible
- Status badge tooltip with description
- Add REMINDER_3_DAYS email template
- Fix maybeSendEmail to respect notification preferences
- Optimize bulk notification email loop

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 12:59:35 +01:00
Matt
9c19661400 Fix iOS download via Content-Disposition header, fix COI gate null check
Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
- Server: presigned GET URLs now include Content-Disposition: attachment header
  when forDownload=true, triggering native browser downloads on all platforms
- Download button uses window.location.href with attachment URL (works on iOS Safari)
- Bulk download uses hidden iframes instead of fetch+blob
- Fix COI gate: getCOIStatus returns null (not undefined) when undeclared,
  so `!== undefined` was always true — changed to `!= null`

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 14:56:09 +01:00
d02b0b91b9 Award shortlist UX improvements + configurable invite link expiry
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m30s
Award shortlist:
- Expandable reasoning text (click to toggle, hover hint)
- Bulk select/deselect all checkbox in header
- Top N projects highlighted with amber background
- New bulkToggleShortlisted backend mutation

Invite link expiry:
- New "Invitation Link Expiry (hours)" field in Security Settings
- Reads from systemSettings `invite_link_expiry_hours` (default 72h / 3 days)
- Email template dynamically shows "X hours" or "X days" based on setting
- All 3 invite paths (bulk create, single invite, bulk resend) use setting

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 22:05:58 +01:00
Matt
b2279067e2 Add LiteLLM proxy support for ChatGPT subscription AI access
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m22s
- Add ai_provider setting: 'openai' (API key) or 'litellm' (ChatGPT subscription proxy)
- Auto-strip max_tokens/max_completion_tokens for chatgpt/ prefix models
  (ChatGPT subscription backend rejects token limit fields)
- LiteLLM mode: dummy API key when none configured, base URL required
- isOpenAIConfigured() checks base URL instead of API key for LiteLLM
- listAvailableModels() returns manualEntry flag for LiteLLM (no models.list)
- Settings UI: conditional fields, info banner, manual model input with
  chatgpt/ prefix examples when LiteLLM selected
- All 7 AI services work transparently via buildCompletionParams()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 15:48:34 +01:00
Matt
014bb15890 Reduce AI costs: switch tagging to gpt-4o-mini, add custom base URL support
Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
- Change AI tagging to use AI_MODELS.QUICK (gpt-4o-mini) instead of gpt-4o for
  10-15x cost reduction on classification tasks
- Add openai_base_url system setting for OpenAI-compatible providers
  (OpenRouter, Groq, Together AI, local models)
- Reset OpenAI client singleton when API key, base URL, or model changes
- Add base URL field to AI settings form with provider examples

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 15:34:59 +01:00
8e5fc18da6 Consolidated round management, AI filtering enhancements, MinIO storage restructure
All checks were successful
Build and Push Docker Image / build (push) Successful in 7m45s
- Fix STAGE_ACTIVE bug in assignment router (now ROUND_ACTIVE)
- Add evaluation form CRUD (getForm + upsertForm endpoints)
- Add advanceProjects mutation for manual project advancement
- Rewrite round detail page: 7-tab consolidated interface
- Add filtering rules UI with full CRUD (field-based, document check, AI screening)
- Add pageCount field to ProjectFile for document page limit filtering
- Enhance AI filtering: per-file page limits, category/region-aware guidelines
- Restructure MinIO paths: {ProjectName}/{RoundName}/{timestamp}-{file}
- Update dashboard and pool page links from /admin/competitions to /admin/rounds

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 09:20:02 +01:00
6ca39c976b Competition/Round architecture: full platform rewrite (Phases 1-9)
All checks were successful
Build and Push Docker Image / build (push) Successful in 7m45s
Replace Pipeline/Stage system with Competition/Round architecture.
New schema: Competition, Round (7 types), JuryGroup, AssignmentPolicy,
ProjectRoundState, DeliberationSession, ResultLock, SubmissionWindow.
New services: round-engine, round-assignment, deliberation, result-lock,
submission-manager, competition-context, ai-prompt-guard.
Full admin/jury/applicant/mentor UI rewrite. AI prompt hardening with
structured prompts, retry logic, and injection detection. All legacy
pipeline/stage code removed. 4 new migrations + seed aligned.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:04:15 +01:00
9ab4717f96 Simplify routing to award assignment, seed all CSV entries, fix category mapping
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m3s
- Remove RoutingRule model and routing engine (replaced by direct award assignment)
- Simplify RoutingMode enum: PARALLEL/POST_MAIN → SHARED, keep EXCLUSIVE
- Remove routing router, routing-rules-editor, and related tests
- Update pipeline, award, and notification code to remove routing references
- Seed: include all CSV entries (no filtering/dedup), AI screening handles duplicates
- Seed: fix non-breaking space (U+00A0) bug in category/issue mapping
- Stage filtering: add duplicate detection that flags projects for admin review

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 14:25:05 +01:00
Matt
382570cebd Pipeline UX: clickable cards, wizard edit, routing rules redesign, category quotas
All checks were successful
Build and Push Docker Image / build (push) Successful in 18s
- Simplify pipeline list cards: whole card is clickable, remove clutter
- Add wizard edit page for existing pipelines with full state pre-population
- Extract toWizardTrackConfig to shared utility for reuse
- Rewrite predicate builder with 3 modes: Simple (sentence-style), AI (NLP), Advanced (JSON)
- Fix routing operators to match backend (eq/neq/in/contains/gt/lt)
- Rewrite routing rules editor with collapsible cards and natural language summaries
- Add parseNaturalLanguageRule AI procedure for routing rules
- Add per-category quotas to SelectionConfig and EvaluationConfig
- Add category quota UI toggles to selection and assignment sections
- Add category breakdown display to selection panel
- Add category-aware scoring to smart assignment (penalty/bonus)
- Add category-aware filtering targets with excess demotion

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 20:10:24 +01:00
Matt
b5425e705e Apply full refactor updates plus pipeline/email UX confirmations
All checks were successful
Build and Push Docker Image / build (push) Successful in 10m33s
2026-02-14 15:26:42 +01:00
c88f540633 Fix pipeline config crashes, settings UX, invite roles, seed expertise tags
- Fix critical crash when clicking Edit on INTAKE stage configs: normalize
  DB fileRequirements shape (type/required → acceptedMimeTypes/isRequired),
  add null guard in getActiveCategoriesFromMimeTypes
- Fix config summary display for all stage types to handle seed data key
  mismatches (votingEnabled→juryVotingEnabled, minAssignmentsPerJuror→
  minLoadPerJuror, deterministic.rules→rules, etc.)
- Add AWARD_MASTER role to invite page dropdown and user router validations
- Restructure settings sidebar: Tags and Webhooks as direct links instead
  of nested tabs, remove redundant Quick Links section
- Seed 38 expertise tags across 7 categories (Marine Science, Technology,
  Policy, Conservation, Business, Education, Engineering)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 11:40:44 +01:00
70cfad7d46 Platform polish: bulk invite, file requirements, filtering redesign, UX fixes
- F1: Set seed jury/mentors/observers to NONE status (not invited), remove passwords
- F2: Add bulk invite UI with checkbox selection and floating toolbar
- F3: Add getProjectRequirements backend query + requirement slots on project detail
- F4: Redesign filtering section: AI criteria textarea, "What AI sees" card,
  field-aware eligibility rules with human-readable previews
- F5: Auto-redirect to pipeline detail when only one pipeline exists
- F6: Make project names clickable in pipeline intake panel
- F7: Fix pipeline creation error: edition context fallback + .min(1) validation
- Pipeline wizard sections: add isActive locking, info tooltips, UX improvements

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 23:45:21 +01:00
331b67dae0 Round system redesign: Phases 1-7 complete
Full pipeline/track/stage architecture replacing the legacy round system.

Schema: 11 new models (Pipeline, Track, Stage, StageTransition,
ProjectStageState, RoutingRule, Cohort, CohortProject, LiveProgressCursor,
OverrideAction, AudienceVoter) + 8 new enums.

Backend: 9 new routers (pipeline, stage, routing, stageFiltering,
stageAssignment, cohort, live, decision, award) + 6 new services
(stage-engine, routing-engine, stage-filtering, stage-assignment,
stage-notifications, live-control).

Frontend: Pipeline wizard (17 components), jury stage pages (7),
applicant pipeline pages (3), public stage pages (2), admin pipeline
pages (5), shared stage components (3), SSE route, live hook.

Phase 6 refit: 23 routers/services migrated from roundId to stageId,
all frontend components refitted. Deleted round.ts (985 lines),
roundTemplate.ts, round-helpers.ts, round-settings.ts, round-type-settings.tsx,
10 legacy admin pages, 7 legacy jury pages, 3 legacy dialogs.

Phase 7 validation: 36 tests (10 unit + 8 integration files) all passing,
TypeScript 0 errors, Next.js build succeeds, 13 integrity checks,
legacy symbol sweep clean, auto-seed on first Docker startup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 13:57:09 +01:00
98f4a957cc Performance optimization, applicant portal, and missing DB migration
Performance:
- Convert admin dashboard from SSR to client-side tRPC (fixes 503/ChunkLoadError)
- New dashboard.getStats tRPC endpoint batches 16 queries into single response
- Parallelize jury dashboard queries (assignments + gracePeriods via Promise.all)
- Add project.getFullDetail combined endpoint (project + assignments + stats)
- Configure Prisma connection pool (connection_limit=20, pool_timeout=10)
- Add optimizePackageImports for lucide-react tree-shaking
- Increase React Query staleTime from 1min to 5min

Applicant portal:
- Add applicant layout, nav, dashboard, documents, team, and mentor pages
- Add applicant router with document and team management endpoints
- Add chunk error recovery utility
- Update role nav and auth redirect for applicant role

Database:
- Add migration for missing schema elements (SpecialAward job tracking
  columns, WizardTemplate table, missing indexes)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 11:04:26 +01:00
09091d7c08 Jury dashboard compact layout, assignment redesign, auth fixes
- Jury dashboard: collapse zero-assignment state into single welcome card
  with inline quick actions; merge completion bar into stats row; tighten spacing
- Manual assignment: replace tiny Dialog modal with inline collapsible section
  featuring searchable juror combobox and multi-select project list with bulk assign
- Fix applicant invite URL path (/auth/accept-invite -> /accept-invite)
- Add APPLICANT role redirect to /my-submission from root page
- Add Applicant label to accept-invite role display
- Fix a/an grammar in invitation emails and accept-invite page
- Set-password page: use MOPC logo instead of lock icon
- Notification bell: remove filter tabs, always show all notifications

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 01:26:19 +01:00
d787a24921 Observer dashboard extraction, PDF reports, jury UX overhaul, and miscellaneous improvements
- Extract observer dashboard to client component, add PDF export button
- Add PDF report generator with jsPDF for analytics reports
- Overhaul jury evaluation page with improved layout and UX
- Add new analytics endpoints for observer/admin reports
- Improve round creation/edit forms with better settings
- Fix filtering rules page, CSV export dialog, notification bell
- Update auth, prisma schema, and various type fixes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 23:08:00 +01:00
5cae78fe0c Fix first-login error, awards performance, filter animation, cache invalidation, and query fixes
- Guard onboarding tRPC queries with session hydration check (fixes UNAUTHORIZED on first login)
- Defer expensive queries on awards page until UI elements are opened (dialog/tab)
- Fix perPage: 500 exceeding backend Zod max of 100 on awards eligibility query
- Add smooth open/close animation to project filters collapsible bar
- Fix seeded user status from ACTIVE to INVITED in seed-candidatures.ts
- Add router.refresh() cache invalidation across ~22 admin forms
- Fix geographic analytics query to use programId instead of round.programId
- Fix dashboard queries to scope by programId correctly
- Fix project.listPool and round queries for projects outside round context
- Add rounds page useEffect for state sync after mutations

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 21:21:54 +01:00
e7c86a7b1b Add dynamic apply wizard customization with admin settings UI
- Create wizard config types, utilities, and defaults (wizard-config.ts)
- Add admin apply settings page with drag-and-drop step ordering, dropdown
  option management, feature toggles, welcome message customization, and
  custom field builder with select/multiselect options editor
- Build dynamic apply wizard component with animated step transitions,
  mobile-first responsive design, and config-driven form validation
- Update step components to accept dynamic config (categories, ocean issues,
  field visibility, feature flags)
- Replace hardcoded enum validation with string-based validation for
  admin-configurable dropdown values, with safe enum casting at storage layer
- Add wizard template system (model, router, admin UI) with built-in
  MOPC Classic preset
- Add program wizard config CRUD procedures to program router
- Update application router getConfig to return wizardConfig, submit handler
  to store custom field data in metadataJson
- Add edition-based apply page, project pool page, and supporting routers
- Fix CSS (invalid sm:fixed-none), Enter key handler (skip textarea),
  safe area insets for notched phones, buildStepsArray field visibility

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 13:21:26 +01:00
f038c95777 Fix Docker build failure: lazy-initialize MinIO client
The production env var check in createMinioClient() was throwing during
`next build` page data collection because MINIO_ACCESS_KEY/SECRET_KEY
aren't available at Docker build time. Changed from eager module-level
initialization to a lazy Proxy pattern that defers client creation to
first actual use, while maintaining backward compatibility with all
existing `minio.method()` call sites.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-05 22:16:29 +01:00
002a9dbfc3 Platform review round 2: audit logging migration, nav unification, DB indexes, and UI polish
- Migrate ~41 inline audit log calls to shared logAudit() utility across all routers
- Add transaction-aware prisma parameter to logAudit() for atomic operations
- Unify jury/mentor/observer navigation into shared RoleNav component
- Add composite DB indexes (Evaluation, GracePeriod, AuditLog) for query performance
- Fix profile page: consolidate dual save buttons, proper useEffect initialization
- Enhance auth error page with MOPC branding and navigation
- Improve observer dashboard with prominent read-only badge
- Fix DI-3: fetch projects before bulk status update for accurate notifications
- Remove unused aiBoost field from smart-assignment scoring
- Add shared image-upload utility and structured logger module

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-05 21:09:06 +01:00
8d0979e649 Comprehensive platform review: security fixes, query optimization, UI improvements, and code cleanup
Security (Critical/High):
- Fix path traversal bypass in local storage provider (path.resolve + prefix check)
- Fix timing-unsafe HMAC comparison (crypto.timingSafeEqual)
- Add auth + ownership checks to email API routes (verify-credentials, change-password)
- Remove hardcoded secret key fallback in local storage provider
- Add production credential check for MinIO (fail loudly if not set)
- Remove DB error details from health check response
- Add stricter rate limiting on application submissions (5/hour)
- Add rate limiting on email availability check (anti-enumeration)
- Change getAIAssignmentJobStatus to adminProcedure
- Block dangerous file extensions on upload
- Reduce project list max perPage from 5000 to 200

Query Optimization:
- Optimize analytics getProjectRankings with select instead of full includes
- Fix N+1 in mentor.getSuggestions (batch findMany instead of loop)
- Use _count for files instead of fetching full file records in project list
- Switch to bulk notifications in assignment and user bulk operations
- Batch filtering upserts (25 per transaction instead of all at once)

UI/UX:
- Replace Inter font with Montserrat in public layout (brand consistency)
- Use Logo component in public layout instead of placeholder
- Create branded 404 and error pages
- Make admin rounds table responsive with mobile card layout
- Fix notification bell paths to be role-aware
- Replace hardcoded slate colors with semantic tokens in admin sidebar
- Force light mode (dark mode untested)
- Adjust CardTitle default size
- Improve muted-foreground contrast for accessibility (A11Y)
- Move profile form state initialization to useEffect

Code Quality:
- Extract shared toProjectWithRelations to anonymization.ts (removed 3 duplicates)
- Remove dead code: getObjectInfo, isValidImageSize, unused batch tag functions, debug logs
- Remove unused twilio dependency
- Remove redundant email index from schema
- Add actual storage object deletion when file records are deleted
- Wrap evaluation submit + assignment update in
- Add comprehensive platform review document

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-05 20:31:08 +01:00
e01d741f01 Fix GPT-5 nano empty response issue with token limits
GPT-5 nano (and other GPT-5 models) use reasoning that consumes
the output token budget. When max_tokens is too low, all tokens
get used by internal reasoning, leaving nothing for the response.

- Add needsHigherTokenLimit() to detect models needing more tokens
- Add getMinTokenLimit() to ensure minimum 16k tokens for GPT-5
- Update buildCompletionParams to apply minimum token limits
- This fixes the No response from AI error with gpt-5-nano

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:02:22 +01:00
c0f318a867 Add country mapping support for imports and geographic map
- Add normalizeCountryToCode utility to convert country names to ISO-2 codes
- Support English, French and common alternate spellings
- Update Typeform import to support country field mapping
- Update Notion import to support country field mapping
- Allow project.update to set/update country with automatic normalization
- Fix geographic distribution map showing empty when country data exists

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 16:13:40 +01:00
0f956cf23f Fix invitation flow by allowing unauthenticated tRPC requests
The middleware was blocking /api/trpc requests for unauthenticated users,
which prevented the accept-invite page from calling the public
validateInviteToken procedure. tRPC handles its own authentication
via procedure middleware, so the NextAuth middleware should allow
all tRPC requests through.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 00:26:05 +01:00
b0189cad92 Add styled notification emails and round-attached notifications
- Add 15+ styled email templates matching existing invite email design
- Wire up notification triggers in all routers (assignment, round, project, mentor, application, onboarding)
- Add test email button for each notification type in admin settings
- Add round-attached notifications: admins can configure which notification to send when projects enter a round
- Fall back to status-based notifications when round has no configured notification

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 00:10:51 +01:00
3be6a743ed Add multiple admin improvements and bug fixes
- Email settings: Add separate sender display name field
- Rounds page: Drag-and-drop reordering with visible order numbers
- Round creation: Auto-assign projects to filtering rounds, auto-activate if voting started
- Round detail: Fix incorrect "voting period ended" message for draft rounds
- Projects page: Add delete option with confirmation dialog
- AI filtering: Add configurable batch size and parallel request settings
- Filtering results: Fix duplicate criteria display
- Add seed scripts for notification settings and MOPC onboarding form

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 23:19:45 +01:00
1d137ce93e Improve notification bell placement and change sender to MOPC Portal
- Move notification bell to sidebar header next to logo (desktop)
- Keep bell in mobile header bar (already well-placed)
- Change email sender name from 'MOPC Platform' to 'MOPC Portal'

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 22:47:24 +01:00
03c031a8b6 Fix rounds management bugs and invitation flow
- Fix rounds list showing 0 projects by adding _count to program.list query
- Fix round reordering by using correct cache invalidation params
- Fix finalizeResults to auto-advance passed projects to next round
- Fix member list not updating after add/remove by invalidating user.list
- Fix invitation link error page by correcting path from /auth-error to /error
- Add /apply, /verify, /error to public paths in auth config

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 22:15:22 +01:00
0277768ed7 Add notification bell system and MOPC onboarding form
Notification System:
- Add InAppNotification and NotificationEmailSetting database models
- Create notification service with 60+ notification types for all user roles
- Add notification router with CRUD endpoints
- Build NotificationBell UI component with dropdown and unread count
- Integrate bell into admin, jury, mentor, and observer navs
- Add notification email settings admin UI in Settings > Notifications
- Add notification triggers to filtering router (complete/failed)
- Add sendNotificationEmail function to email library
- Add formatRelativeTime utility function

MOPC Onboarding Form:
- Create /apply landing page with auto-redirect for single form
- Create seed script for MOPC 2026 application form (6 steps)
- Create seed script for default notification email settings

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 21:30:25 +01:00
e2782b2b19 Add background filtering jobs, improved date picker, AI reasoning display
- Implement background job system for AI filtering to avoid HTTP timeouts
- Add FilteringJob model to track progress of long-running filtering operations
- Add real-time progress polling for filtering operations on round details page
- Create custom DateTimePicker component with calendar popup (no year picker hassle)
- Fix round date persistence bug (refetchOnWindowFocus was resetting form state)
- Integrate filtering controls into round details page for filtering rounds
- Display AI reasoning for flagged/filtered projects in results table
- Add onboarding system scaffolding (schema, routes, basic UI)
- Allow setting round dates in the past for manual overrides

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 19:48:41 +01:00
3986da172f Fix GPT-5 API compatibility and add AIUsageLog migration
- Add AIUsageLog table migration for token tracking
- Fix GPT-5 temperature parameter (not supported, like o-series)
- Add usesNewTokenParam() and supportsTemperature() functions
- Add GPT-5+ category to model selection UI
- Update model sorting to show GPT-5+ first

GPT-5 and newer models use max_completion_tokens and don't support
custom temperature values, similar to reasoning models.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 15:04:16 +01:00
c0ce6f9f1f Fix GPT-5 max_completion_tokens parameter detection
GPT-5 and newer models require max_completion_tokens instead of max_tokens.
Added usesNewTokenParam() to detect GPT-5+ models separately from reasoning
model restrictions (temperature, json_object, system messages).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 13:08:01 +01:00
928b1c65dc Optimize AI system with batching, token tracking, and GDPR compliance
- Add AIUsageLog model for persistent token/cost tracking
- Implement batched processing for all AI services:
  - Assignment: 15 projects/batch
  - Filtering: 20 projects/batch
  - Award eligibility: 20 projects/batch
  - Mentor matching: 15 projects/batch
- Create unified error classification (ai-errors.ts)
- Enhance anonymization with comprehensive project data
- Add AI usage dashboard to Settings page
- Add usage stats endpoints to settings router
- Create AI system documentation (5 files)
- Create GDPR compliance documentation (2 files)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 11:58:12 +01:00
d068d9b6f6 Improve AI filtering error handling and visibility
- Add listAvailableModels() and validateModel() to openai.ts
- Improve testOpenAIConnection() to test configured model
- Add checkAIStatus endpoint to filtering router
- Add pre-execution AI config check in executeRules
- Improve error messages in AI filtering service (rate limit, quota, etc.)
- Add AI status warning banner on round detail page for filtering rounds

Now admins get clear errors when AI is misconfigured instead of silent flags.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 10:46:38 +01:00
90e3adfab2 Implement Prototype 1 improvements: unified members, project filters, audit expansion, filtering rounds, special awards
- Unified Member Management: merge /admin/users and /admin/mentors into /admin/members with role tabs, search, pagination
- Project List Filters: add search, multi-status filter, round/category/country selects, boolean toggles, URL persistence
- Audit Log Expansion: track logins, round state changes, evaluation submissions, file access, role changes via shared logAudit utility
- Founding Date Field: add foundedAt to Project model with CSV import support
- Filtering Round System: configurable rules (field-based, document check, AI screening), execution engine, results review with override/reinstate
- Special Awards System: named awards with eligibility criteria, dedicated jury, PICK_WINNER/RANKED/SCORED voting modes, AI eligibility
- Dashboard resilience: wrap heavy queries in try-catch to prevent error boundary on transient DB failures
- Reusable pagination component extracted to src/components/shared/pagination.tsx
- Old /admin/users and /admin/mentors routes redirect to /admin/members
- Prisma migration for all schema additions (additive, no data loss)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 16:58:29 +01:00