Design for surfacing the already-live Grand Final document upload (PDF + 1-min
video) to the 9 confirmed finalists via a dashboard banner, a read-only judge
review page (Finals Jury group + admins), a Final Documents panel on both the
team and mentor views, and email + in-app reminders (auto cron + manual blast).
Reuses the existing legacy FileRequirement anchor, upload mechanics, and
notification pipeline. Grounded in verified prod state.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
External lunch attendees had no way to pick their own dish — an admin had to set
it inline and no email was ever sent. (Marine added herself as an external
expecting a dish-selection link and never received one.)
Adds:
- ExternalAttendee.inviteSentAt + additive migration
- HMAC-signed external lunch token (mirrors finalist-token)
- Public no-login picker page /lunch/pick/[token] — dish + allergens + notes,
gated by the lunch change deadline, read-only after
- tRPC getExternalByToken / setExternalPick (public) + sendExternalInvite (admin)
- Auto-send invite on createExternal when an email is present; per-row resend
button + status chip (Invited / Picked / no email) in the logistics screen
- Unpicked externals chased by the lunch reminder cron + manual "Send reminders"
- sendExternalDishInviteEmail (branded). Page + email title use the configurable
venue ("Lunch at {venue}") rather than "grand finale"
Tests: token roundtrip/tamper/expiry, selectUnpickedExternals filter,
get/set-by-token happy + deadline + bad-token, createExternal auto-send,
cron external reminders. Full suite 303 passing; build clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
After review, two additions to the multi-role UX section:
1. Replace static-priority post-login redirect with context-aware
"go where the work is" via new user.getDefaultDashboard() — a
juror+observer landing during an active jury round goes to /jury
even though observer has no work; falls back to static priority
when no role has actionable work.
2. Standardize the role switcher's location across all dashboards.
Extract shared useRoleSwitcher hook + new RoleSwitcherPill that
renders in the top-right of every layout, including admin (which
currently puts switching in the bottom-left sidebar pill).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Captures the per-round toggle, side-panel deeper display, "How scores
are calculated" explainer dialog, and the cross-round contamination
fixes for getProjectDetail and getProjectRankings.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>