Repository navigation
Conversation
The list drew only after hydration plus a tRPC batch. A server page now reads the list, the visitor's registrations and projects and hands them to the unchanged client page; its dates print on the venue calendar so the server (UTC) and the browser agree. Cold load to the first card, 5 runs, 1440px, median: 436 to 334 ms (warm 190 to 158).
The page waited on the registrations, then on the submission, the event and the submission window for the event it picked. The server page reads the registrations, picks the same event (the URL's, else the first still open), and reads the other three with it. PrefetchedPage accepts an async reads function for this. Cold load to the submission notice, median of 5: 878 to 488 ms (warm 412 to 232).
…mber pass The dashboard's next step waited on the registrations and then up to four more queries; the server page works out which the client will ask for (the same checks as the page) and reads them. The club page also read member.myPass after load; it is prefetched now. Cold load median of 5: dashboard checked-in hacker 1247 to 530 ms (warm 420 to 279), club pass QR 514 to 290 (warm 203 to 150).
… list Each drew its list only after hydration plus a tRPC batch. Server pages read events.listAll, hackathon.listAll and the bans list for the unchanged client pages, and the dates they print move to the venue calendar. Cold load median of 5: /admin 493 to 308 ms, /admin/attendees 452 to 393, /admin/hackathons 1113 to 359.
…cations The dashboard waited on the edition, then on the applications page and the stats. The server page reads the edition, the first page of applications and the analytics. The dates in the applications table move to the venue calendar, and the registration controls (a deadline and inputs in the organiser's own time zone, which the server cannot know) are drawn after hydration so both renders agree; without that gate React threw #418. Cold load median of 5: 672 to 480 ms (warm 315 to 189).
The edition console waited on the overview and then the checklist. Server pages read the edition list, the overview and the checklist. shortTime moves to the venue clock so server and browser print the same times. Cold load median of 5: /admin/judging 560 to 365 ms, an edition 963 to 495.
Attendance and the workshop table drew after hydration plus a tRPC batch. A server page reads both for the current term and the session dates print on the venue calendar. Cold load median of 5: 858 to 613 ms (warm 321 to 251).
… sign-up Each page held a loading screen until its first tRPC batch returned. Server pages read the first reads of lead, lead/[id], initiatives, subteams, club/bootcamp and judge/register for the unchanged client pages. Cold load median of 5: lead 582 to 369 ms, a project 695 to 432, initiatives 437 to 301, subteams 643 to 475, club/bootcamp 621 to 392, judge/register 699 to 419.
Every search on the admin roster answered 500: "operator does not exist: uuid = text". The filter is shared by the paged roster, which runs as a relational query (db.query.hackathonParticipants.findMany), and inside that Drizzle renders every column in a raw sql template against the participants alias. The user-name and email subquery therefore compared "hackathonParticipants"."id" (uuid) with its own user_id (text), and read name and email off the participants alias too. The user table now has a hand-written alias in that subquery. Checked on a production build against the local Docker database: "example.test" matches the 8 seeded attendees through their user email, "casey" 1, "zzzz" 0.
perf(mainweb): ship the rest of the portal's first data with the HTML
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
|
Visit the preview URL for this PR (updated for commit 7cd2942): https://hacklytics2027--pr-583-e9h0x2jg.web.app (expires Fri, 13 Nov 2026 17:54:50 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 Sign: c48ba34db61581e25fe2978355160b5eefe0e83f |
[Medium impact] The broadest reach is faster first data across signed-in portal workflows. Fix the dashboard’s late rejection handler before merging. Findings
|
| ["user.me", undefined, c.user.me()], | ||
| ]} | ||
| reads={async (c) => { | ||
| const me = c.user.me(); |
There was a problem hiding this comment.
Profile errors escape the fallback
If user.me fails while registrations or portal context are still loading, its promise has no rejection handler. dehydratePrefetched attaches its catch only after this callback returns, so the failure reaches the server as an unhandled rejection instead of staying inside the intended fallback. Attach a catch when starting me, before the first await.
Rest of the signed-in portal ships its first data with the HTML; admin roster search fixed (#582).
Note
Medium Risk
Touches many high-traffic portal routes and prefetch wiring; wrong cache keys or async prefetch branches could cause stale or missing client data, though failures fall back to client fetch.
Overview
Ships initial tRPC data with the HTML by moving many portal
page.tsxfiles to thin server wrappers aroundPrefetchedPage, with the interactive UI extracted into*Page.tsxclient components (admin club, bootcamp, hackathons, judging, dashboard-related routes, club bootcamp, etc.). Dashboard prefetch is now async and conditional: it mirrors the client’s “next step” logic to warmhackathon.myRegistrations, portal context, and submission/judging/results queries when applicable.Hackathon admin roster search fixes the Drizzle
EXISTSsubquery to aliasusersexplicitly souser_idcompares against the real user primary key instead of a mis-resolved participant column (stopping 500s on search). Attendees tab polish defersRegistrationControlsuntil client hydration for timezone-correct deadlines and formats attendee timestamps withvenueFormatfor venue-consistent display. Club hub prefetch also pullsmember.myPass.Smaller UX tweaks alongside the moves: e.g. bootcamp admin session rows use venue time formatting; hackathons list page is extracted similarly for prefetch.
Reviewed by Cursor Bugbot for commit 7cd2942. Bugbot is set up for automated code reviews on this repo. Configure here.