Commit Graph

323 Commits

Author SHA1 Message Date
9b3a9f6cbf feat: enhance project search to include all criteria, add AI tag generation button
- 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>
2026-03-01 14:42:37 +01:00
dd004baf79 feat: add View Project links to admin tables, conditionally show Awards tab
- 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>
2026-03-01 14:37:45 +01:00
2f1136646e feat: ranking UI improvements - highlight advancing projects, expandable reviews, view project link
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 14:34:32 +01:00
36560a1837 fix: assign project to round on creation (create ProjectRoundState)
- Add optional roundId field to project.create mutation input schema
- After project creation, update project.roundId FK and create a
  ProjectRoundState record (state: PENDING) when roundId is supplied
- Pass selectedRoundId from the new-project form to createProject.mutate()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 14:31:08 +01:00
25e06e11e4 feat: add all missing fields to project update mutation and edit form
Adds competitionCategory, oceanIssue, institution, geographicZone,
wantsMentorship, and foundedAt to the tRPC update mutation input schema
and the admin project edit form UI (with CountrySelect + Switch).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 14:28:26 +01:00
f200eda692 fix: score distribution chart bars + add binaryDecision backfill script
All checks were successful
Build and Push Docker Image / build (push) Successful in 11m15s
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>
2026-02-27 11:14:02 +01:00
ba7f068b1e fix: show project title, team & country in ranking rows instead of truncated IDs
Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
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>
2026-02-27 11:08:30 +01:00
28ae934c57 feat: add ranking criteria textarea + auto-rank toggle to evaluation config UI
All checks were successful
Build and Push Docker Image / build (push) Successful in 10m11s
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>
2026-02-27 10:36:37 +01:00
f055926b6f docs(02-03): complete Advance Top N plan — SUMMARY, STATE, ROADMAP updated
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m57s
- Phase 2 complete: all 3 plans done (DASH-01 through DASH-07 fulfilled)
- REQUIREMENTS.md: marked DASH-05, DASH-06, DASH-07 complete
- ROADMAP.md: Phase 2 updated to Complete (3/3 plans)
- STATE.md: advanced to Phase 2 complete, added 3 new decisions
2026-02-27 09:56:07 +01:00
a6f3945337 feat(02-03): add Advance Top N dialog + batch-reject to RankingDashboard
- 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
2026-02-27 09:53:49 +01:00
84031a4e04 docs(02-02): complete RankingDashboard plan — SUMMARY, STATE, ROADMAP updated
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 09:50:02 +01:00
6512e4ea2a feat(02-02): implement full RankingDashboard component
- Replace stub with complete drag-and-drop ranked project list (DASH-01, DASH-02)
- localOrder in useState with useRef init guard prevents snap-back (DASH-03)
- Per-category DndContext (STARTUP / BUSINESS_CONCEPT) with SortableProjectRow
- AI-order rows show dark-blue rank badge; admin-reordered show amber '(override)' badge
- Sheet panel lazy-loads trpc.project.getFullDetail on row click (DASH-04)
- Per-juror evaluation breakdown with score, binary decision, feedback text
- 'Run Ranking' button in header triggers triggerAutoRank mutation
- Empty categories show placeholder message (no empty drag zone)
- Zero TypeScript errors; build passes
2026-02-27 09:48:06 +01:00
c851acae20 docs(02-01): complete ranking-tab-entry-point plan — SUMMARY, STATE, ROADMAP updated
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 09:43:57 +01:00
8f71527353 feat(02-01): register Ranking tab in round detail page + create component stub
- Create src/components/admin/round/ranking-dashboard.tsx (stub with placeholder text)
- Import RankingDashboard in round detail page.tsx
- Add Ranking tab entry guarded by isEvaluation (uses existing BarChart3 icon)
- Add TabsContent block rendering RankingDashboard with competitionId + roundId props
2026-02-27 09:41:59 +01:00
68422e6c26 feat(02-01): add saveReorder mutation to ranking router
- Define ReorderEvent local type (category, orderedProjectIds, reorderedBy, reorderedAt)
- Add saveReorder adminProcedure accepting snapshotId, category, orderedProjectIds
- Append-only log: reads existing reordersJson, appends new event, persists full array
- Returns { ok: true } on success
2026-02-27 09:40:03 +01:00
7b407528f6 docs(01-04): complete auto-trigger plan — SUMMARY, STATE, ROADMAP updated
- 01-04-SUMMARY.md: full plan summary with 7 procedure list, deviations, build status
- STATE.md: plan 4/4 complete, decisions recorded, session updated
- ROADMAP.md: Phase 1 all 4 plans complete
- REQUIREMENTS.md: RANK-09 and RANK-10 marked complete
2026-02-27 01:08:26 +01:00
c310631480 feat(01-04): add auto-trigger hook + triggerAutoRank + retroactiveScan
- evaluation.ts: add triggerAutoRankIfComplete (module-level, not exported)
  - Checks total/completed required assignments for round
  - Reads autoRankOnComplete + rankingCriteria from round configJson
  - 5-minute cooldown guard on AUTO snapshots
  - Fire-and-forget via void call after isCompleted=true (never awaited)
  - Notifies admins via AI_RANKING_COMPLETE / AI_RANKING_FAILED
- ranking.ts: add triggerAutoRank procedure (RANK-09)
  - Admin manual trigger reading criteria from round configJson
  - Creates MANUAL snapshot with QUICK mode
- ranking.ts: add retroactiveScan procedure (RANK-10)
  - Scans ROUND_ACTIVE / ROUND_CLOSED rounds for auto-rank configured
  - Skips rounds with existing RETROACTIVE snapshots
  - Runs sequentially to avoid rate limits
- ranking.ts: router now has 7 total procedures
2026-02-27 01:05:10 +01:00
d1d64cb6f7 feat(01-03): register rankingRouter in appRouter
- Import rankingRouter from './ranking'
- Add ranking: rankingRouter after filtering entry
- Build verified: passes typecheck and production build
2026-02-27 00:59:53 +01:00
4683bb8740 feat(01-04): add AI_RANKING_COMPLETE + AI_RANKING_FAILED notification types
- Added AI_RANKING_COMPLETE and AI_RANKING_FAILED to NotificationTypes const
- Added BarChart3 / AlertTriangle icons in NotificationIcons
- Added normal / high priorities in NotificationPriorities
2026-02-27 00:58:18 +01:00
7c4dffaf84 feat(01-03): create tRPC rankingRouter with 5 admin-gated procedures
- parseRankingCriteria: parse natural-language criteria, returns ParsedRankingRule[]
- executeRanking: fetch+rank both categories, persist CONFIRMED RankingSnapshot
- quickRank: parse+execute in one step, persist QUICK RankingSnapshot
- listSnapshots: list snapshots for a round ordered by createdAt desc
- getSnapshot: fetch full snapshot by ID with NOT_FOUND guard
- All procedures use adminProcedure (SUPER_ADMIN, PROGRAM_ADMIN only)
- Casts to Prisma.InputJsonValue via unknown to satisfy strict TS
2026-02-27 00:57:57 +01:00
890795edd9 docs(01-01): complete RankingSnapshot schema plan — SUMMARY + state updates
- Create 01-01-SUMMARY.md with schema decisions, deviations, self-check results
- Update STATE.md with 01-01 decisions and session info
- Update ROADMAP.md phase 1 progress (2/4 summaries)
- Mark requirements RANK-01, RANK-05, RANK-08, RANK-09 complete

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 00:55:35 +01:00
af9528dcfb feat(01-01): extend EvaluationConfigSchema with ranking fields
- Add rankingEnabled: z.boolean().default(false)
- Add rankingCriteria: z.string().optional()
- Add autoRankOnComplete: z.boolean().default(false)
- All fields are optional/defaulted for backwards compatibility with existing rounds
- npm run typecheck passes cleanly
2026-02-27 00:52:15 +01:00
91bc100559 feat(01-01): add RankingSnapshot model + enums to schema.prisma
- Add RankingTriggerType enum (MANUAL, AUTO, RETROACTIVE, QUICK)
- Add RankingMode enum (PREVIEW, CONFIRMED, QUICK)
- Add RankingSnapshotStatus enum (PENDING, RUNNING, COMPLETED, FAILED)
- Add RankingSnapshot model with roundId/triggeredById FKs, criteria/results JSON fields, AI metadata
- Add Round.rankingSnapshots back-relation (RoundRankingSnapshots)
- Add User.rankingSnapshots back-relation (TriggeredRankingSnapshots)
- Create migration 20260227000000_add_ranking_snapshot
- Regenerate Prisma client (prisma.rankingSnapshot accessible)
2026-02-27 00:51:07 +01:00
aa383f53f8 feat(01-02): create ai-ranking.ts service with criteria parsing and ranking
- Add parseRankingCriteria() — parses natural-language criteria via OpenAI JSON mode
- Add executeAIRanking() — anonymizes projects (P001…), calls OpenAI, de-anonymizes results
- Add quickRank() — one-shot helper that parses + ranks both categories in parallel
- Add fetchAndRankCategory() — fetches eligible projects from Prisma and calls executeAIRanking
- compositeScore: 50% normalised avgGlobalScore + 50% passRate + tiny tiebreak bonus
- Projects with zero SUBMITTED evaluations are excluded (not ranked last)
- All project IDs anonymized before OpenAI — no PII in prompts
- Follows ai-filtering.ts pattern: getOpenAI, logAIUsage with action RANKING, classifyAIError
2026-02-27 00:48:09 +01:00
7193abd87b feat(01-02): add RANKING to AIAction type in ai-usage.ts
- Add | 'RANKING' to the AIAction union type
- Enables logAIUsage calls with action: 'RANKING'
2026-02-27 00:46:04 +01:00
44946cb845 docs: initialize project — AI ranking, advancement & mentoring
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:32:28 +01:00
8cc86bae20 docs: map existing codebase
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:14:08 +01:00
c96f1b67a5 feat: add admin advancement summary card and advance column in assignments table
- 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>
2026-02-25 15:19:30 +01:00
79bd4dbae7 feat: add juror progress dashboard with evaluation.getMyProgress query
- 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>
2026-02-25 15:15:08 +01:00
2a61aa8e08 feat: add showJurorProgressDashboard toggle to EvaluationConfig
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 15:12:23 +01:00
a327962f04 feat: render advance criterion on juror evaluation page and fix related renderers
- 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>
2026-02-25 15:11:24 +01:00
6c97ce3ed9 feat: server-side support for advance criterion in upsertForm and submit
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 15:08:21 +01:00
0edb50cd3a feat: add advance criterion type to evaluation form builder
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>
2026-02-25 15:04:58 +01:00
bf86eeee7f Add implementation plan for advance criterion and juror progress dashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 14:40:56 +01:00
38658d2611 Add design doc for advance criterion and juror progress dashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 14:34:50 +01:00
0a96960ae2 Fix race condition: deduplicate startMutation calls between autosave and submit
All checks were successful
Build and Push Docker Image / build (push) Successful in 10m5s
Use a shared startPromiseRef so autosave and handleSubmit reuse the same
in-flight "create evaluation" promise instead of firing duplicate requests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 17:49:35 +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
230347005c Show 100% progress for closed/archived rounds in Round Pipeline
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m23s
Closed and archived rounds now always display a full progress bar instead
of relying on the computed completionRate which is 0 for non-evaluation rounds.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 21:07:18 +01:00
91563f3f47 Add Reviews column to Projects tab showing evaluation submission progress
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m36s
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>
2026-02-23 20:38:43 +01:00
5ece50268b Improve reports page: active round defaults, compact project summary, status labels
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m34s
- Default round selectors to ROUND_ACTIVE instead of first round (StageAnalytics, JurorConsistency, Diversity, PDF export)
- Reimagine Project Reports as compact dashboard: summary stats, status chips, top-10 table
- Map ELIGIBLE status to "Special Award" display label

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 20:18:14 +01:00
61c4d0eb75 Fix evaluation double-click submit: autosave was blocking the submit button
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m35s
Root cause: submit button was disabled when autosaveMutation.isPending was true.
If the 3-second autosave timer fired while the user clicked Submit, the click
was silently swallowed. User had to wait for autosave to finish, then click again.

Fixes:
- Remove autosaveMutation.isPending from submit button disabled state
- Cancel pending autosave timer when submit starts (prevents race condition)
- Add isSubmittingRef guard to prevent autosave from firing during submit
- Reset submitting flag on validation failure or submit error

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 19:14:37 +01:00
3bc6552f47 Fix multi-click submit bug and add draft submit indicator on juror dashboard
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m24s
- 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>
2026-02-23 17:29:13 +01:00
ab2c73bad2 Add 5-second auto-refresh for dashboard Activity feed
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m0s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 17:15:42 +01:00
feccd269f7 Add COI_REASSIGNED and MANUAL_REASSIGNED to prod SQL insert script
All checks were successful
Build and Push Docker Image / build (push) Successful in 10m0s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 16:12:33 +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
f7bc3b4dd2 Fix learning hub upload: ensure mopc-learning bucket exists
All checks were successful
Build and Push Docker Image / build (push) Successful in 10m4s
The getUploadUrl procedure generated a presigned PUT URL without first
checking that the mopc-learning bucket exists, causing all uploads to fail.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 20:36:06 +01:00
09cc49d920 Fix score distribution chart and add auto-assign for transfer dialog
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m30s
- Fix bar chart CSS: percentage heights now resolve correctly with flex-1
  and absolute bottom-anchored bars
- Add Auto-assign button to transfer assignments dialog that distributes
  projects across eligible jurors balanced by load, preferring jurors who
  haven't completed all evaluations and are under their cap

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 20:16:15 +01:00