Editing one profile field silently erases every other field in that subdocument, because the update replaces the whole nested object instead of merging.
Root cause
server/modules/user/service.js:14-35 (updateProfile) copies whole nested objects:
if (updateData.profile !== undefined) allowedFields.profile = updateData.profile;
if (updateData.handles !== undefined) allowedFields.handles = updateData.handles;
if (updateData.preferences !== undefined) allowedFields.preferences = updateData.preferences;
server/modules/user/repository.js:16-22 passes them straight to Mongoose:
return await User.findByIdAndUpdate(id, updateData, { new: true, runValidators: true });
A top-level nested object becomes $set: { profile: {…} }, which replaces the entire profile subdocument. Correct partial update needs dot-notation ($set: { "profile.bio": … }).
Failure scenario
A user signs up via GitHub → profile.avatar = GitHub avatar, handles.github = login, handles.codeforces = e.g. tourist. They later edit only their bio → frontend sends { profile: { bio: "hi" } } → profile becomes { bio: "hi" }; avatar, college, location, skills are gone. Likewise { handles: { leetcode: "x" } } erases handles.github/handles.codeforces. The wiped handles.github also degrades GitHubService.#getToken (its user.handles.github fallback, github/service.js:50).
Fix
Flatten the incoming nested fields to dot-notation before $set (merge), so only the provided keys are updated.
Dedup
No issue references profile-update data loss; no PR touches user/service.js or user/repository.js. Distinct from #301/#302/#303/#304. Unreported.
Contributing as part of Elite Coders Summer of Code (ECSoC 2026).
Editing one profile field silently erases every other field in that subdocument, because the update replaces the whole nested object instead of merging.
Root cause
server/modules/user/service.js:14-35(updateProfile) copies whole nested objects:server/modules/user/repository.js:16-22passes them straight to Mongoose:A top-level nested object becomes
$set: { profile: {…} }, which replaces the entireprofilesubdocument. Correct partial update needs dot-notation ($set: { "profile.bio": … }).Failure scenario
A user signs up via GitHub →
profile.avatar= GitHub avatar,handles.github= login,handles.codeforces= e.g.tourist. They later edit only their bio → frontend sends{ profile: { bio: "hi" } }→profilebecomes{ bio: "hi" };avatar,college,location,skillsare gone. Likewise{ handles: { leetcode: "x" } }eraseshandles.github/handles.codeforces. The wipedhandles.githubalso degradesGitHubService.#getToken(itsuser.handles.githubfallback,github/service.js:50).Fix
Flatten the incoming nested fields to dot-notation before
$set(merge), so only the provided keys are updated.Dedup
No issue references profile-update data loss; no PR touches
user/service.jsoruser/repository.js. Distinct from #301/#302/#303/#304. Unreported.Contributing as part of Elite Coders Summer of Code (ECSoC 2026).