fix(profile): stop avatar changes 405-ing on POST /api/user/update - #39
Merged
Conversation
Setting a profile photo — from the camera roll or from a URL — surfaced an
error in EditProfileView and never refreshed the local User. The avatar did
reach the server, so a later relaunch showed it, which made this read as flaky
rather than as a hard failure.
Both uploadAvatar and setAvatarFromURL funnelled through applyAvatarUrl, which
POSTed /api/user/update to apply the returned URL. That route exports PATCH
only, so the second call always returned 405 (live-confirmed). The D1 verb-fix
pass caught updateProfile and updateUserSettings and missed this third site.
- Delete applyAvatarUrl. /api/user/avatar/upload and /api/user/avatar/from-url
each already run prisma.user.update and answer with { url, user }, so the
saved user comes straight off the first response — there is no second write
to make, and nothing to fix up client-side
- Both paths fall back to currentUser() if a response arrives without `user`,
so an older deployment sending the bare { url } still refreshes the profile
instead of leaving a stale avatar on screen
- Rewrite APIClientAvatarTests, which asserted the broken two-call shape by
enqueueing a second response. It now pins the request count at one and
asserts that /api/user/update is never called, so the regression can't come
back quietly; the bare-{url} fallback is covered for both entry points
Verified: 828 tests, 0 failures (iPhone 16 · 302E002E-…,
-parallel-testing-enabled NO, E2E skipped).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KD1sv3y8YWsDBiG31tUJWo
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
D4 — Tier 0, a live regression in shipped code. Setting a profile photo (camera roll or URL) surfaces an error in
EditProfileViewand never refreshes the localUser. The avatar does land on the server, so a later relaunch shows it — which is why this reads as flaky rather than as a hard failure.Both
uploadAvatarandsetAvatarFromURLfunnelled throughapplyAvatarUrl, which POSTed/api/user/update. That route exportsPATCHonly → 405, live-confirmed. The D1 verb-fix pass caughtupdateProfileandupdateUserSettingsand missed this third call site.The fix
applyAvatarUrlis deleted, not repaired. Reading the backend:/api/user/avatar/uploadand/api/user/avatar/from-urleach already runprisma.user.update({ data: { avatar } })and return{ url, user }. There was never a second write to make — the saved user comes straight off the first response.currentUser()when a response arrives withoutuser, so a deployment sending the bare{ url }still refreshes the profile rather than leaving a stale avatar on screen.Tests
APIClientAvatarTestsasserted the broken shape — it enqueued a second response for the follow-up write. Rewritten to:/api/user/updateis never called (so the regression can't return quietly),{url}fallback for both entry points.8 tests → 13.
Testing
xcodebuild test -parallel-testing-enabled NO -skip-testing:InterlinedListTests/E2EReadOnlyTests— 828 tests, 0 failures (823 baseline + 5 net new).Note
work-consolidation.mdalso lists "drop the 5 force-unwraps atAPIClient.swift:224-229" under D4. Those went in #38, along with the other 16, when the multipart builders collapsed ontopostMultipartRawData.🤖 Generated with Claude Code