Repository navigation
Release 0.11.0: Yuyu sync 3, hackathon suite, mobile API and /help - #48
Merged
Merged
Conversation
Unit, PostgreSQL integration (local receiver) and production e2e coverage, the quality gate flag for the e2e receiver, and docs/WEBHOOKS.md with event types, payloads, signature verification, retries and SSRF rules. (cherry picked from commit c113c53) Ported to Space Works Events: Events' docs kept with the webhook text added (the beat delivers every 15 seconds; PENDING_PAYMENT status; renumbered migration); the scheduler test covers webhooks as a beat job; the integration suite drives Events' approve and cancel actions. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Events can register people in teams: capacity counts teams and solo registrants as units, organisers approve, reject and promote whole teams, leaders share a join link or add members, and an optional "looking for a team" list matches solo registrants with teams. Includes the migration, team pages, organiser Teams view, badges/CSV/export/report support, and unit and PostgreSQL integration tests. Design contract: docs/TEAMS.md. (cherry picked from commit 44ff7fb) Ported to Space Works Events: migration renumbered; the team rules went into Events' split code (lib/rsvpCore/{reserve,submit,manual,team}.ts, validators/teams.ts, outbox/team.ts, email/team.ts in the Space Works email layout, the RSVP lifecycle/cancel/admin actions, the split check-in client); team names reach Events' server-rendered badges; every new page reads through a lib/views reader for the split frontend; teams and tickets are not combined yet (refused both ways); Yuyu's mobile API files dropped and the docs reworded; PENDING_PAYMENT added to team status types. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… pages - Team settings in the Create Event dialog - Solo registrants can join a team through a join link (event-locked move that frees their place and promotes the waitlist) - Paged, searchable organiser Teams view; check-in lookup matches team names - Team-specific register wording; seeker form resets after save - Playwright teams journey; ticket, team and join pages send no-store in production (proxy.ts) (cherry picked from commit 512934c) Ported to Space Works Events: the join page's signed-in registration and the Guests panel's team page load through their lib/views readers; the ticket page's join form comes from lib/teamTicketSection; capability-page caching lives in lib/pageSecurity (both proxies); Events' Create Event and registration card keep their paid-ticket wording for individual events; the team name search went into Events' check-in lookup; mobile API docs dropped. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Whole-team approve, reject and promote, automatic team promotion, moves into a team, leader removals, disbanding, organiser team deletion and its undo now emit one registration.status_changed per member after commit, with the same minimal payload as individual RSVPs; a leader adding a member emits registration.created. setTeamStatusTx and promoteOldestWaitlistedUnit return the emissions, and team cores collect them in teamTransaction and emit once the transaction has committed. Team undo snapshots now carry each member's custom check-in list records, and restoring a team deletion (or a last-member deletion) recreates them for lists that still belong to the event, like the single-RSVP undo. (cherry picked from commit c535f46) Ported to Space Works Events: promotion webhooks go into Events' cancel and organiser-remove actions (rsvp-admin helper returns them for emitting after commit); docs keep Events' wording without the mobile API. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entrants (teams or solo registrants) submit projects within a window; a new JUDGE collaborator permission gives judges an isolated scoring workspace with conflict-of-interest checks; organisers manage a weighted rubric, judge assignments, disqualification, awards and a ranked results table with CSV export, and publish results to a public results page and optional project gallery with an entrant email. Design contract: docs/HACKATHON.md. (cherry picked from commit 6f0ac88) Ported to Space Works Events: migrations renumbered; JUDGE flags live in Events' eventCapabilities; validators/outbox/email split into lib/validators/judging.ts, lib/outbox/judging.ts and lib/email/judging.ts (Space Works email layout); every judging page and panel reads through lib/views readers (submission editor view loaded by readers, so SubmissionSection is a plain component); the ticket page's submission card is computed in its loader; solo projects are retired in the shared move-into-team helper; submission snapshots go through Events' rsvp-admin; /submit links are capability pages (no-store, robots); mobile API parts dropped. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- proxy.ts: /submit/{token} and /account/submissions/{eventId} get the same
private no-store Cache-Control as ticket and team links.
- Integration tests: join-by-link applies the solo project rules and still
emits registration webhooks; one team undo snapshot restores the project,
judging record and check-in list records, and older snapshot formats still
restore; a JUDGE-only collaborator is refused by canManageRegistrationsFor,
RSVP actions, check-in lists, email drafts, webhooks and the attendee CSV.
- Docs: judging rows and the JUDGE grant in PERMISSIONS.md; managing judging
stays owner/admin (not MANAGE_REGISTRATIONS), recorded in HACKATHON.md;
judging webhook events listed in FUTURE_PHASES.md.
(cherry picked from commit b4e80c1)
Ported to Space Works Events: the capability-page rule lives in lib/pageSecurity (/submit and /account/submissions added); Events' permission matrix keeps its own rows and gains the JUDGE column and judging rows; the integration tests drive Events' Server Actions.
Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The team management page (/team/:token) rendered with no site chrome: no
header, no main landmark for the skip link, and no side gutter on phones.
It now uses Yuyu's site chrome like /ticket/:token.
- Arrow keys in the registration form's "How are you taking part?" group
dropped keyboard focus out of the dialog when moving to "Join with a link",
because the form remounted. The team choice now stays mounted.
- Resetting the team management link emailed nothing, so a leader who lost the
tab lost the team page. The new link is now queued to the leader
(team-created, reason "reset").
- The solo-policy dropdown ("Can people sign up without a team?") had no
accessible name in Create event and Publishing.
- /ticket/:token (now showing Join a team and the seeker list) sent the
site-wide strict-origin-when-cross-origin Referrer-Policy header; it now
sends no-referrer like the team pages.
- A confirmed incomplete team was told the organisers can't approve it, on
events without approval; it is now told how many members to add.
- The join page promised "Register below" when the team was full or
registration closed, and hid the "already registered" hint after closing
although joining with an existing registration still works then.
- The check-in desk lookup on team events said "Name or email" though it also
matches team names.
(cherry picked from commit e99815a)
Ported to Space Works Events: the reset email went into lib/email/team.ts and lib/outbox/team.ts; the team-aware search label into the split check-in client; Events' RsvpForm (with tickets) hides the fields while waiting for a join link.
Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Organiser Teams view: Approve on an incomplete team stays focusable (aria-disabled) and is described by visible helper text via aria-describedby instead of a title tooltip. - Team page: the "Looking for a team" empty state says when everyone is already invited (or has a pending request) instead of "No one is looking". - Register dialog: the "Join with a link" note has one icon and says the link opens the team's page to register straight into it. - Create Event dialog: team sizes drop native min/max so only the inline message shows; it is a polite live region describing the invalid input, focus moves to that input, and the duplicate dialog alert is gone (server validation unchanged). - Declined teams: Rename, join/management link resets, Make leader and "looking for members" are hidden on the team page and refused in the lib/core/teams.ts cores under the event lock; removing members, disbanding and leaving still work. docs/TEAMS.md updated. - Public event page: the going/places count refreshes after a successful registration (router.refresh after /api/rsvp revalidates), for team and individual events alike. - Tests: e2e assertions for each UI change in tests/e2e/teams.spec.ts and an integration test for declined-team refusals in teams.db.test.ts. (cherry picked from commit a679581) Ported to Space Works Events: kept Events' Create Event dialog and registration card (paid tickets), with the refresh after registering. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- /submit/{token} (and /team/{token}) rendered with no site chrome: no
header, no main landmark for the skip link, no phone gutter. Both now use
Yuyu's site chrome like /ticket/{token}.
- robots.txt did not disallow /submit/, unlike every other bearer-capability
path; it does now (ROUTES.md updated).
- Judge workspace lost keyboard focus: opening a submission unmounted the
focused list button (focus fell to <body>) and "All submissions" did the
same. Focus now moves to the project heading, and back to the project's
button on return.
- saveJudgeReviewAction wrote the scores before validating the comment, so an
over-long comment returned an error yet left the scores changed. The review
input is now validated before any write.
- The Settings tab's "Put it on your website" snippets read window.location
during the hydrating render, a server/client text mismatch (intermittent
React #418 on the Settings tab, where submissions are turned on). The
origin is now read with useSyncExternalStore after hydration.
- Turning submissions on from Settings moved the card to the new Judging tab
with only "Judging settings saved."; the toast now says where it went.
- New tests/e2e/judging.spec.ts covers the core journey: submissions on,
rubric, team and solo submissions, a JUDGE-only judge scoring by keyboard,
close, rank, award, publish/unpublish/republish without duplicate emails.
(cherry picked from commit d146a43)
Ported to Space Works Events: Events already had the hydration-safe origin and /submit/ in robots; /submit/ added to the site chrome prefixes; the hydration test uses Events' EventManageMore props.
Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit a25ffae) Ported to Space Works Events: the unit counts went into Events' view loaders (event header, Analytics, super-admin activity as a plain record) and the split dashboard-home rows/cards; mobile API files dropped. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Submissions on a draft/offline/cancelled event: the judging settings card
warns while the switch is on (with a link to Overview for drafts) and the
save toast repeats it; entrants' tickets on a draft or offline event say
when submissions open instead of showing nothing, and the editor's window
line no longer says "Submissions aren't open right now".
- Results publish hint follows the judging status: open judging first (not
started), close judging to finalise (open), pick winners and publish (closed).
- The organiser's Score tab uses organiser copy: an empty rubric links to the
rubric editor on Setup, and "not started" says to open judging there.
- Judges tab separates "Invited judges" (JUDGE grants, with an empty state
linking to Settings) from "Organisers who can also judge"; the sub-tab count
is invited judges only.
- Tab strips scroll the active tab into view inside the row (never the page)
on mount and on change, smooth unless reduced motion: shared underline tabs,
link tabs and the dashboard sub-tabs (useActiveTabIntoView).
- Disqualify lists the awards the project holds and, after publication, warns
that the live results page changes; reinstating now confirms and says lost
awards are not given back.
- Judging CSV review times are ISO 8601 in the event timezone with an explicit
offset, and the header names the zone ("Review submitted (Asia/Kolkata)").
- "The destination stream closed early." is React aborting a streamed render
when the browser disconnects (Next.js logs it with a digest); onRequestError
no longer turns it into an ops alert. Documented in production-operations.
- Tests: tests/unit/judging-panel-copy.test.ts,
tests/unit/instrumentation-request-error.test.ts, CSV timezone in the
judging integration suite, and new e2e steps in tests/e2e/judging.spec.ts.
(cherry picked from commit e24da7a)
Ported to Space Works Events: the not-live submission card comes from lib/teamTicketSection; the shared window phase is reused by lib/submissionEditorView.
Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A REJECTED team or registration got the generic "only confirmed registrations" refusal and a notice saying the section would open once confirmed. Refuse with a declined message instead and tell the entrant. (cherry picked from commit ceb6c69) Ported to Space Works Events: the declined flag goes through lib/submissionEditorView (Events loads the editor view in readers). Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After the team-registration merge the TEAM-event header shows a "Places taken" detail line, pushing the judging sub-tab row a few pixels below an 844px viewport. The test is about the active tabs being scrolled into their rows, so assert horizontal containment within the row instead. (cherry picked from commit 5bc6272) Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
teams.spec.ts and judging.spec.ts both counted through 198.51.100.x in parallel workers. With the team-registration e2e additions the ranges overlap, so both specs share a per-IP action limit and judging publish was refused with "Too many judging updates". Use 203.0.113.x instead. (cherry picked from commit 35d9726) Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Server-side paging for every large list on team, guest, check-in and judging screens. Each page goes through a read-only action that re-checks its screen's permission, scopes by event and organisation, uses the search rate-limit bucket, and orders with a unique id tiebreak. - Guests · Teams: 50 at a time with Load more, server search and status filter. - Guests · People: 50 at a time (createdAt, id keyset) via loadAttendeesPage; filters, search and chip counts on the server; 250 cap removed; series page shares the list. - Export emails: new GET /api/exports/events/:eventId/attendee-emails for every match of the current filters (attendee-CSV access, 404 on denial, audited with filter names only); ExportEmailsButton removed. - Move to team picker: searchMoveTargets, teams with room only, 20 at a time on a (nameKey, id) keyset; 200 cap removed. - Invites: numbered pages of 50 with email search via loadInvitesPage (MANAGE_INVITATIONS). - Check-in desk and venue station: Recent check-ins 25 at a time (checkedInAt, id) with Load more and refresh merging; CSV links to the full attendee export for exporters only. - Custom check-in list roster: 100 at a time with server search and per-chip counts (CHECK_IN). - Team page and ticket page: seekers, teams looking for members, invitations and requests 20 at a time with search. - Account → Registrations: numbered pages of 50 per section. - Judge Score list: 25 at a time with To score / In progress / Reviewed counts and search; visibility, assignments and conflicts still applied in SQL. - Judging → Submissions: 50 at a time with server status filter and search. - Judging → Results: numbered pages of 50 over the whole ranking (ranks and ties unchanged); Awards picker searches ranked SUBMITTED projects 20 at a time; Judges progress from aggregates. - Public project gallery: 24 per page with ?page= and ?q=, page canonical URLs, searches not indexed; public results bounded by award limits. - Shared PageNumberPager (44px targets) and useLoadMoreFocus: Load more / Show more move focus to the first new row. - Docs (TEAMS, HACKATHON, DESIGN, FEATURES, PERMISSIONS, ROUTES, SECURITY, MOBILE_API, CHANGELOG) and unit plus PostgreSQL integration tests. (cherry picked from commit 445d6f0) Ported to Space Works Events: Events' view readers carry the paging (series, check-in desk and station, account registrations, projects); the account paging helpers live in the frontend-safe lib/accountLimits.ts; Recent check-ins paging is a hook in the split check-in desk with a thin loadRecentCheckIns action; docs condensed to Events' DESIGN/SECURITY layout. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add tests/e2e/pagination.spec.ts: on a seeded large event, Guests · People pages 50 at a time with whole-event chip counts, Load more and the server search (name and email) reach a guest past page one; Guests · Teams loads 50 then the rest; Judging → Results uses numbered pages of 50 with ranks computed over the whole ranking; Guests · Invites uses numbered pages of 50 with an email search. List it in docs/TESTING.md. (cherry picked from commit 40b972e) Ported to Space Works Events: TESTING.md entry folded into Events' prose paragraph. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…core next) - Automatic judge assignment: preview then apply an even, deterministic plan of N judges per submitted project from the picked pool (invited judges by default, organisers only when ticked), never a conflicted judge; keep or start over; apply re-plans under the event lock, refuses a changed plan, sets judgesSeeAll=false and reviewsPerProject, and is audited (JUDGES_AUTO_ASSIGNED). New Event.reviewsPerProject (1..20, CHECK) and ScoreNormalization enum (migration 20261025000000_judging_ops). - Judging -> Progress (owner/admin): summary with an editable review target (audited JUDGING_REVIEW_TARGET_UPDATED), projects below target, per-judge completion, outlier scores and stale reviews, numbered pages of 25. - Fairer scores: raw and z-score adjusted results with an owner/admin switch (audited JUDGING_SCORE_NORMALIZATION_CHANGED); Results, Awards and the CSV (new Raw score / Adjusted score columns) follow the choice. - Score next project: server-picked next project for a judge within their visibility, auto-advance after submitting, "all caught up" state. - Fix (review): automatic assignment now adopts work judges started without an assignment while judges saw every project (scores, drafts, submitted reviews) as assignments that count towards N, so applying (which switches to assigned-only) never locks a judge out of their own work or over-assigns already reviewed projects; without see-all, submitted unassigned reviews still count and their judge isn't re-picked. The preview, toast and audit report the adopted count. - Fix (review): a "Start over" re-run on an unchanged event no longer removes and re-adds the same assignments; pairs in both lists stay put. (cherry picked from commit 33c32e5) Ported to Space Works Events: migration renumbered to 20261104030000_judging_ops; scoreNormalizationSchema in lib/validators/judging.ts; the Progress tab loads through Events' JudgingPanel view reader. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Saved views: SavedView model and migration (name/params CHECKs), address-bar filters with per-list allow-lists, a Views menu (presets, own and shared views, save, manage, copy link) on People, Teams, Submissions, Results and Progress; permission re-checked per list, scoped by event and organisation, audited SAVED_VIEW_* with the list name only. - New server filters with counts: People "Not checked in", Teams "Looking for members", Submissions "Not submitted" (entrants without a submitted project), Results "Unscored" / "Fewer than 2 judges", Progress list chips. - Filtered CSV exports: People, Teams (new route, TEAM_LIST_EXPORTED) and Judging Results/Submissions (JUDGING_SUBMISSIONS_EXPORTED) export exactly the filters showing, streamed server-side in bounded batches through a shared formula-safe helper; empty 404 on denial or bad parameters. - Feedback responses load as numbered pages of 25 instead of stopping at 250. - Remove next-auth SessionProvider (it forced a client re-render that left a hidden duplicate dashboard panel); header, footer and RSVP form read the session from a small store. - Fix: TEAM_LIST_EXPORTED and JUDGING_SUBMISSIONS_EXPORTED are listed on the super-admin Security page (SECURITY_AUDIT_ACTIONS) and in docs/SECURITY.md; a unit test now requires every export route's audit action in that list. - Fix: the Results "Export CSV" link carries the active score chip (scored=unscored/underTwo), so the file matches the table. - Fix: the Submissions "Not submitted" view can be exported (entrants), with an entrant-specific reason when disabled. - Fix: saved-view menus read the viewer's own views separately from shared ones, and the dashboard reads each list on its own, so many shared views can no longer hide a user's own views or another list's views. - Docs: FEATURES, PERMISSIONS, TEAMS, HACKATHON, ROUTES, DESIGN, TESTING, SECURITY and CHANGELOG. (cherry picked from commit 1009c92) Ported to Space Works Events: migration renumbered to 20261104040000_saved_views; saved views and feedback paging load through Events' panel view readers; the attendee CSV keeps Events' canAccessEvent check and ticket/order columns; organiser team access widened to canManageRegistrationsFor (Yuyu 5ba1897) so registration grant holders who see Guests · Teams can act on it; single badge/ID-card downloads stay off the Security page list. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Seed saved-views guests with emails slugged from the full name, so the two team leaders no longer share an attendee key, and match the Views menu by its own label so the organisation and account menus (seeded "Views ..." names) no longer collide with it. (cherry picked from commit d3fbff3) Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Gallery: Newest (default), A-Z and Awards first orders, an Award winners filter and award badges once results are published, all in SQL with id tiebreaks and validated, shareable search params. GET form via next/form and links (works without JS), count in a polite live region, canonical without filter params. Results page gains the same search when it lists more than 10 winners. Visibility rules and public DTOs unchanged. (cherry picked from commit d201974) Ported to Space Works Events: gallery and results query parsing runs in Events' projects/results view readers. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Gallery (/{org}/{event}/projects): ?q= search, ?sort=newest|az|awards
(Newest default, id tiebreaks) and ?filter=winners with its count, all in
SQL (lib/galleryQuery.ts); filter, awards order and badges only once
results are published, so winners are never revealed early (builds on
d201974).
- Results page (/{org}/{event}/results): the same ?q= search once more than
10 winners are listed.
- Fix (review): gallery award badges put the place first and wrap instead of
truncating (new Chip `wrap` option), so a long award name can no longer
hide which place a project won.
- Fix (review): PublicAwardDto carries `isTop`, set before the results search
filters awards, so a searched view never gives a lower-ranked award the
headline accent style.
- Tests: unit render test for AwardBadges, integration check that `isTop`
survives filtering, e2e badge text updated.
(cherry picked from commit 947e7ba)
Ported to Space Works Events: Chip wrap applied to Events' Space Works chip sizing.
Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Wait for the search itself (q in the URL and the updated count) before reading gallery cards, since the URL already carried the filter and sort, and wait for the no-JS result cards before reading them. (cherry picked from commit a009c86) Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Times just after midnight rendered as "0:05 AM" on the server under Node 20 (its ICU resolves en-GB `hour12: true` to the h11 cycle) but as "12:05 AM" in the browser, a hydration mismatch (React #418) on every dashboard list showing such a time. CI runs Node 20 and ran the e2e suite at 00:0x UTC, so the filtered-exports and judging specs failed. Format with `hourCycle: "h12"` in formatTime and the sign-up closing summary, and pin the 12 o'clock hour in unit tests. (cherry picked from commit 2c22352) Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Webhook requests now carry x-spaceworks-event-id, x-spaceworks-event-type and x-spaceworks-signature with the SpaceWorks-Webhooks/1 user agent, and the signing-secret key label is spaceworks-org-webhook-signing-secret-v1 (nothing was encrypted under the old label). Settings copy, the webhook guide and the verification example say Space Works. The team join and ticket pages read saved RSVPs under Events' swe:rsvp: prefix (RSVP_STORAGE_PREFIX, shared with the RSVP form); the ported yuyu:rsvp: keys never matched, so a saved ticket was never offered. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The agent guide lists team registration, hackathon judging, webhooks, custom check-in lists and saved views. Ported docs no longer refer to Yuyu's mobile API, which Events doesn't have, and TEAMS.md says who manages teams (owners, admins and MANAGE_REGISTRATIONS holders). The judging-permissions unit test no longer leaves unused variables. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Splits the 32 files the Yuyu port left over the ESLint max-lines limit into focused parts behind their original import paths: lib/core/teams, lib/core/judging and lib/core/judgingOps become folders re-exporting the same public names; "use server" action files keep every exported action (helpers and the restoreRsvp body moved to sibling folders); large components move state into hooks and sections into sibling folders; the teams and judging integration suites split by topic with shared helpers (402 integration and 86 e2e tests listed before and after). The event broadcast delivery moved to lib/outbox/broadcast.ts. Unit tests that load lib/core/teams now mock lib/eventAccess. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eck-in lists Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he ticket designer Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Disqualifying can refund the entry fee in full; reinstating then left the project submitted unpaid, and a disqualified project can't pay again. Reinstatement is refused with a clear message while a fee order exists and no longer holds money; a waived or kept fee reinstates as before. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When the buyer had already asked (ALREADY_REQUESTED), the check stored no refundRequestId, so a later No said the request was already handled and organisers got an extra notice. The open request's id is now stored on the check. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claims are read, capped and withdrawn by registration, so a transferred ticket handed the previous holder's claims to the new holder. A transfer is refused while the holder's claims are SUBMITTED, APPROVED or PAID, with OPEN_CLAIMS for the web action and the mobile API (new error code). Adds tests/integration/money-audit-orders.db.test.ts covering this and the cancel, refund-request reopen and attendance fixes. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds secretEncrypted, manageTokenHash, keyHash, requestHash and emailHash to the forbidden view and mobile DTO fields, and a unit test that reads prisma/schema.prisma so a new such column must be listed. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ord write Retried refunds, settles, payment links, orders, checkouts, cancels, transfers, refund requests, claims (both POSTs), claim decisions, check-ins and organiser decisions could act twice. authedMobileRoute, eventRoute and judgingRoute take an idempotent option (idempotentRequest: body read once, multipart matched by fields and files, ticket tokens never kept); POST /rsvp needs a key when signed in. Exemptions (sign-in routes, read-only POSTs, the attendance link, PATCH and DELETE) are documented and pinned by tests/unit/mobile-idempotency-coverage.test.ts; the OpenAPI marks the header required. Tests: a replayed partial refund refunds once, a replayed order registers once. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner decision: JUDGE, MENTOR and REVIEW_APPLICATIONS collaborators file and withdraw their own claims on that event only. Mobile fileClaims and the claim routes (anyGrant) now match the web action; the judge, mentor and reviewer workspaces show the Finance claim form. FINANCE.md, MOBILE_API.md and TESTING.md updated. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…awards, frozen counted reviews, recusal) Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drops the stale "Deferred" mobile lines from .github/yuyu-reviewed.txt (every one is named on a cherry-pick line; the weekly check logic still reports 0 pending), notes the deliberate Android fingerprint variable name, says the native apps are not built yet and lists the sync 3 deferrals in FUTURE_PHASES.md. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ites, desk-owed cancels, waive refusal, transfers with claims, staff claims) Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he new fields The ineligible check-in and list check-in read the registration's own and team's application status in the same query instead of a second count; the crew schema test covers withdrawApplication; the migration impact table lists 20261119030000_admission_audit_fixes. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ew, accepted-only stage claims, admission fresh eyes, data export, secret fields) Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scripts/check-reserved-slugs.mjs runs read-only before the VPS updater's migrator and in the Helm migration Job, so an organisation on /attend, /crew, /help, /submit or /team stops the deploy with nothing migrated; Render gets a documented manual check. /order and /verify-mfa are reserved too, with a test that every top-level route is. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ile keys and audit-fix columns Adds the WebhookEndpoint/WebhookDelivery tables, the payout ledger and ticket-design owner triggers, the four mobile and webhook unique keys, the remaining CHECK families, and the 20261119* columns and cascade. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Admission notices stay urgent: their offers carry a deadline to accept. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ayment return-link keys; ci: frontend catalog check Explains what a mismatched key does to those HMACs across replicas. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Complete 0.11.0 changelog with upgrade notes and the migration list; sync 3 plan records the final audit. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rage, 0.11.0) Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s for the frontend The judging panel imported FINALIZE_REASON_MAX_LENGTH from lib/core/judgingRounds, which pulls the database client into the split frontend build. The limit now lives in lib/validators/judgingRounds.ts. CI builds the split frontend too. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…I hosting runs New specs hard-coded cf-connecting-ip, which CI's hosting runs ignore (they trust x-real-ip), so the whole suite shared one rate-limit bucket. Direct /api/rsvp posts now send Origin (the split proxy refuses unsafe requests without it), the split spec passes the registrations view its searchParams, and the request-actor test pins in-process check-in delivery. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…/SMTP, upload e2e traces Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A split-hosted page render reads a dozen or more views from the API, each counted against the visitor's 300/min global bucket, so a few quick dashboard changes broke the page. Authenticated peer view reads now skip it, as a single-server render does; peer actions keep their own limit. Also match the Invite button's full accessible name in the team matching spec. Co-Authored-By: Shaan-Shoukath <shaanshoukath4522@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Release 0.11.0: the third Yuyu sync at full parity, the Space Works hackathon suite (judging rounds, Mentor Desk, volunteer shifts, multi-stage admission, per-stage reimbursements), the mobile API for a future Space Works app, and the in-app guide at
/help.This PR also carries the 35 commits that were already on local
devbefore this work started: paid teams, event finance and the ticket designer, with their review fixes.Every branch was built from
dev, independently reviewed, fixed, and merged locally. A final seven-track audit followed, and its findings were fixed. Planning and decisions are indocs/plans/yuyu-sync-3.md.Features
Yuyu parity (sync 3). All 44 Yuyu commits since sync 2 are ported or reviewed. The weekly check reports 0 pending, and a structural re-diff of the schema, routes, actions, mobile API, help, outbox, webhooks and environment found nothing missing.
no-storeand no-referrer on signed-in and token pages.Event crew.
Attendance confirmation.
/attendpage, plus reminders and share links.Judging rounds (Space Works design).
Mentor Desk (Space Works design).
Volunteer shifts (Space Works design).
Multi-stage admission (any event, free or paid).
Per-stage reimbursements.
Mobile API (
/api/mobile/v1; the app itself is not built yet).In-app guide
/help.Decisions (owner)
docs/manualis kept unchanged.Deferred (in
docs/FUTURE_PHASES.md): per-member team payment, the award/reservation reimbursement flow, the native apps, and a Google mobile nonce.Split-hosting fix found by CI (please review). In split hosting, a page render reads a dozen or more views from the API, and each read counted against the visitor's 300/min global API limit. A few quick dashboard changes then broke the page. The website's authenticated view reads (gateway key checked) now skip that bucket, as a single-server render does. Peer actions and every other API request keep their limits (
proxy.ts,docs/DEPLOYMENT_SPLIT.md, unit-tested). The remaining CI fixes were test-only:Originon direct API posts in the new e2e specs;Before merging (action required)
docs/production-operations.md, "Reserved organisation addresses".MFA_ENCRYPTION_KEYmust be identical on every replica. It now also keys mobile idempotency and payment return links.VERSIONto 0.11.0, which publishes release images.Checks
Run locally on
devat the head of this PR (Windows 11, Node 24):npm run lint,npx next typegen && npx tsc --noEmitnpm run test:unitvps-installeranddocker-entrypointtests (they pass on Linux CI), plus a load timeout incheck-production-envthat passes when run alonenpm run test:integration, on a database migrated from scratchprisma migrate deploy→db:verify→ reserved-slug checknpm run buildandnpm run build:frontend(split frontend, no database/mail/Redis/storage code)--checkThe full e2e suite (including the payment specs and
test:e2e:production) was not run locally because of memory limits on this machine. CI runs it.Every branch was independently reviewed before merging. The final audit covered decisions, Yuyu parity, the end-to-end hackathon flow, Mentor Desk, judging, money, security/privacy/tenancy and deploy safety; all of its findings were fixed in
fix/audit-*andchore/deploy-hardening.🤖 Generated with Claude Code