You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Last sprint shipped the state machine and GET /api/v1/status. What's missing is the RSVP submission endpoint, plus swapping the mock singleton file for real Ticket 5 singleton reads.
Tasks
Swap mock singletons for real ones
In src/lib/status/service.ts, replace reads from mock-singletons.ts with getSingleton() calls to Ticket 5's singleton service.
What this accomplishes: The dashboard state machine now uses admin-configured dates instead of hardcoded ones. Changing dates in /admin/settings now actually affects what applicants see.
Delete or rename src/lib/status/mock-singletons.ts to make it obvious it's no longer used.
What this accomplishes: Prevents future confusion where a dev updates the mock file expecting behavior to change and doesn't realize it's dead code.
Handle the case where a singleton hasn't been set (returns null). Reasonable default behavior: if registration-open is null, treat as "not yet open." If confirm-by is null, treat as "no deadline yet" (which means past-deadline logic doesn't kick in).
What this accomplishes: The system doesn't crash if an admin forgot to set a date. It fails safe — applicants can't submit, admitted users can still RSVP.
RSVP submission endpoint
Implement saveRsvp(userId, payload) in src/lib/status/service.ts. Fetches the user, confirms decisionStatus === 'admitted' (only admitted users can RSVP), validates the payload against a Zod schema, checks confirm-by hasn't passed, sets rsvpStatus, postAcceptanceResponses, rsvpSubmissionTime.
What this accomplishes: The core RSVP logic. Non-admitted users can't RSVP, so a waitlisted user can't sneak in as if they'd been admitted. Deadline enforcement is server-side.
Define the Zod schema for RSVP responses. At minimum this includes attendance ('confirmed' | 'unconfirmed'), and any post-acceptance question fields (dietary restrictions, t-shirt size, etc.).
What this accomplishes: RSVP is a smaller form than the application, but still needs validation. The exact fields depend on what questions HackBeanpot wants to ask post-acceptance — coordinate with whoever knows the current requirements.
Wire POST /api/v1/post-acceptance to call saveRsvp. Returns { ok: true } on success, 400 on validation failure, 403 if the user isn't admitted, 410 (Gone) if past confirm-by.
What this accomplishes: The endpoint the RSVP form on /rsvp calls. Status codes let the frontend display specific errors.
Auth gating
Wire requireUser() into GET /api/v1/status and POST /api/v1/post-acceptance.
What this accomplishes: Only signed-in users can check their status or submit an RSVP. Session-based user identification replaces the placeholder query param.
Update getPortalStatus to read userId from the session instead of the query string.
What this accomplishes: Same as Ticket 2's cleanup — removes the temporary shim from the last sprint.
Read-your-own-writes verification
Manually test: sign in as an admitted user, submit an RSVP, refresh the dashboard, confirm the dashboard shows the post-RSVP state (whatever that looks like — confirmed attendance, "see you at the event," etc.).
What this accomplishes: End-to-end proof the state machine sees the RSVP write immediately, without cache issues or stale reads.
Definition of done
The status endpoint uses real singleton values, not the mock file.
Admitted users can submit an RSVP via the frontend and it persists.
Context
Last sprint shipped the state machine and
GET /api/v1/status. What's missing is the RSVP submission endpoint, plus swapping the mock singleton file for real Ticket 5 singleton reads.Tasks
Swap mock singletons for real ones
src/lib/status/service.ts, replace reads frommock-singletons.tswithgetSingleton()calls to Ticket 5's singleton service./admin/settingsnow actually affects what applicants see.src/lib/status/mock-singletons.tsto make it obvious it's no longer used.registration-openis null, treat as "not yet open." Ifconfirm-byis null, treat as "no deadline yet" (which means past-deadline logic doesn't kick in).RSVP submission endpoint
saveRsvp(userId, payload)insrc/lib/status/service.ts. Fetches the user, confirmsdecisionStatus === 'admitted'(only admitted users can RSVP), validates the payload against a Zod schema, checksconfirm-byhasn't passed, setsrsvpStatus,postAcceptanceResponses,rsvpSubmissionTime.'confirmed' | 'unconfirmed'), and any post-acceptance question fields (dietary restrictions, t-shirt size, etc.).POST /api/v1/post-acceptanceto callsaveRsvp. Returns{ ok: true }on success, 400 on validation failure, 403 if the user isn't admitted, 410 (Gone) if pastconfirm-by./rsvpcalls. Status codes let the frontend display specific errors.Auth gating
requireUser()intoGET /api/v1/statusandPOST /api/v1/post-acceptance.getPortalStatusto readuserIdfrom the session instead of the query string.Read-your-own-writes verification
Definition of done
requireUser().