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
fix: align request payloads with backend DTOs ahead of forbidNonWhitelisted (#594)
* fix: align request payloads with backend DTOs ahead of forbidNonWhitelisted
The boundless-nestjs backend (PR #187) is flipping its global
ValidationPipe from forbidNonWhitelisted: false to true. Today any
unknown body field is silently stripped; after the flip, sending such
a field produces a 400. This commit fixes every front-end -> back-end
payload the audit flagged.
1. Team posts (CreateTeamPostModal, ContactTeamModal,
team-detail page).
- lib/api/hackathons/teams.ts: replaced `contactInfo: string` and
`contactMethod` with `contactInfo?: TeamContactInfo` matching the
backend shape `{ telegram?, discord?, email? }`. Added a
readTeamContact() helper that flattens the sparse object back to
`{ method, value }` for UI display.
- CreateTeamPostModal: form schema keeps the `{ method, value }`
UX, but onSubmit projects to `{ contactInfo: { [method]: value } }`
before calling the api. github and other were removed from the
method enum because the backend cannot store them. Edit-mode
initial-data hydrates from readTeamContact().
- ContactTeamModal: replaced direct string access with
readTeamContact() and used contact.method/value throughout. The
github icon case was dropped since github is no longer a valid
method.
- team-detail page: same readTeamContact() flattening for the
Contact card.
2. Judging score (lib/api/hackathons/judging.ts, useScoreForm).
The submitJudgingScore request used `comment` for the global
per-judge note, but the backend ScoreSubmissionDto names the field
`notes`. Renamed the interface field and the call site. Per-criterion
`comment` stays because CriterionScoreDto does accept it.
3. Submission update (hooks/hackathon/use-submission.ts).
Added a pickUpdateSubmissionFields() whitelist mapping to the
backend UpdateSubmissionDto. The update path now strips:
- participationType, teamId, teamName (Create-only)
- organizationId, hackathonId, participantId (server-derived)
- per-entry email on teamMembers (TeamMemberDto has no email)
...before PATCH /hackathons/submissions/:id. The form continues to
send the full shape; the hook filters at the API boundary so future
callers are also protected.
4. User profile (lib/api/auth.ts).
Removed the `preferences` block from UpdateUserProfileRequest. The
backend UpdateProfileDto has no such field; users use the dedicated
/users/settings/* endpoints for appearance / language / timezone /
notification toggles. The wide type was the same kind of unknown-
field door the audit is closing.
5. Hackathon update (lib/api/hackathons.ts).
UpdateHackathonRequest was `Partial<Hackathon> & { rewards? }`,
which let any Hackathon-shape field (id, organizationId, status,
creatorId, ...) leak into PUT /hackathons/:id. Narrowed to just
`{ rewards?: HackathonRewards }` since that is the only field
actually sent today (JudgingResultsTable's rank-override save).
Out of scope (separate pre-existing bugs to file):
- PUT /hackathons/:id has no matching backend route; the rank-
override save in JudgingResultsTable is broken regardless of #187.
- POST /users/earnings/claim does not match backend /users/earnings/
withdraw.
- POST /organizations/:id/invite does not match backend /invitations.
Backend #188 (global ThrottlerGuard + 429 handling): no frontend
changes needed. lib/api/api.ts already honours Retry-After and
exponential backoff (1s, 2s, 4s) for three retries before surfacing
a RATE_LIMIT_EXCEEDED error code.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(submissions): project teamMembers entries to backend TeamMemberDto shape
Found during code review of the previous commit on this branch.
The strip on teamMembers only removed `email`, but the frontend
SubmissionFormData also lets each entry carry `avatar` — and the
backend TeamMemberDto only has { userId, name, username?, role }.
Sending `avatar` would 400 once forbidNonWhitelisted lands.
Switched from a deny-list strip (`{ email: _email, ...rest }`) to an
explicit project-down to the four backend fields. Same defense-in-
depth pattern as the outer pickUpdateSubmissionFields whitelist.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@@ -86,13 +90,12 @@ export function CreateTeamPostModal({
86
90
maxRoles,
87
91
`You can add at most ${maxRoles} open role${maxRoles===1 ? '' : 's'} (the team is capped at ${effectiveTeamMax} member${effectiveTeamMax===1 ? '' : 's'} including you)`
88
92
),
89
-
contactMethod: z.enum([
90
-
'email',
91
-
'telegram',
92
-
'discord',
93
-
'github',
94
-
'other',
95
-
]),
93
+
// contactMethod stays on the form for UX (radio-style selector)
94
+
// but is NOT sent to the backend as a separate field. Backend stores
95
+
// contact as a sparse object keyed by channel (TeamContactInfo);
96
+
// onSubmit transforms { contactMethod, contactInfo } into that shape.
97
+
// github / other were dropped because the backend cannot store them.
0 commit comments