Fixed critical issues with profile picture URL not being saved in MongoDB for all user types (User, Admin, Administrative Head). Implemented proper Cloudinary integration for all profile picture uploads.
- Problem: Regular users couldn't upload profile pictures at all
- Root Cause:
- The PUT handler in
/api/user-profiledidn't includeprofilePicturein the update for regular users - Only
phoneandAddresswere being updated - The UserProfile component had no UI for profile picture uploads
- The PUT handler in
- Impact: Regular users couldn't update their profile pictures
- Status: ✅ FIXED
- Problem: Profile pictures were being base64 encoded instead of uploaded to Cloudinary
- Root Cause:
- The code was converting files to base64 strings:
data:${value.type};base64,${base64} - This is inefficient for database storage and leads to large document sizes
- The Cloudinary upload endpoint existed but wasn't being used
- The code was converting files to base64 strings:
- Impact: Large MongoDB documents, inefficient storage, poor performance
- Status: ✅ FIXED
- Problem: The GET
/api/user-profileendpoint didn't returnprofilePicturefor regular users - Root Cause: The response object for regular users was missing the
profilePicturefield - Impact: Frontend couldn't display saved profile pictures for regular users
- Status: ✅ FIXED
- Problem: Phone and Address were required for regular user updates, preventing profile-picture-only updates
- Root Cause: Validation logic was too strict
- Impact: Users couldn't update profile picture without updating phone and address
- Status: ✅ FIXED
File: app/api/user-profile/route.js
Added uploadToCloudinary() helper function that:
- Uploads files directly to Cloudinary instead of base64 encoding
- Stores only the secure URL in MongoDB (much smaller)
- Uses correct MIME type detection
- Returns the Cloudinary URL for storage
async function uploadToCloudinary(file) {
try {
const arrayBuffer = await file.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
return new Promise((resolve, reject) => {
const uploadStream = cloudinary.uploader.upload_stream(
{
folder: 'profile-pictures',
resource_type: 'auto',
},
(error, result) => {
if (error) {
reject(error);
} else {
resolve(result.secure_url);
}
}
);
uploadStream.end(buffer);
});
} catch (error) {
throw error;
}
}Changes for Administrative Head (adminHead role):
- ✅ Profile picture upload now uses Cloudinary
- ✅ Profile picture is properly saved to MongoDB
- ✅ Added logging for debugging
Changes for Admin (admin role):
- ✅ Profile picture upload now uses Cloudinary
- ✅ Profile picture is properly saved to MongoDB
- ✅ Response includes profilePicture field
Changes for Regular User (default role):
- ✅ NEW: Now supports profile picture uploads
- ✅ Made phone and address optional (can update just profile picture)
- ✅ Profile picture is properly saved to MongoDB via Cloudinary
- ✅ Response includes profilePicture field
- ✅ Field validation improved to require at least one field
Changes for Regular User:
- ✅ Now returns
profilePicturefield in response - ✅ Consistent with Admin and Administrative Head responses
return NextResponse.json(
{
success: true,
user: {
_id: user._id,
userName: user.userName,
email: user.email,
phone: user.phone,
address: user.Address,
age: user.age,
userId: user.userId,
timeOfLogin: user.timeOfLogin,
profilePicture: user.profilePicture // ✅ Now included
}
},
{ status: 200 }
);File: app/user/components/UserProfile.js
Added profile picture functionality:
- ✅ Profile picture preview in the profile card
- ✅ Profile picture upload UI in the edit modal
- ✅ File validation (image type, max 5MB)
- ✅ Visual feedback when image is selected
- ✅ Proper FormData handling for file upload
New Features:
- Profile picture display with fallback to initial
- "Choose Image" button in edit modal
- Real-time preview of selected image
- Visual confirmation of selection
- Uses FormData for proper multipart/form-data request
All three user types now have consistent profile picture handling:
User Collection:
{
...,
profilePicture: "https://res.cloudinary.com/...", // Cloudinary URL
...
}Admin Collection:
{
...,
profilePicture: "https://res.cloudinary.com/...", // Cloudinary URL
...
}AdministrativeHead Collection:
{
...,
profilePicture: "https://res.cloudinary.com/...", // Cloudinary URL
...
}-
Regular user profile picture upload
- Upload new picture
- Verify URL saved in MongoDB
- Verify picture displays after refresh
- Replace existing picture
-
Admin profile picture upload
- Upload new picture
- Verify URL saved in MongoDB
- Verify picture displays after refresh
-
Administrative Head profile picture upload
- Upload new picture
- Verify URL saved in MongoDB
- Verify picture displays after refresh
-
Error Handling
- Invalid file type (not an image)
- File too large (>5MB)
- Network error during upload
- Cloudinary service unavailable
-
Edge Cases
- Update profile picture without other fields (regular user)
- Update other fields without profile picture
- Replace profile picture with another
- Clear profile picture
{
"success": true,
"message": "Profile updated successfully",
"user": {
"_id": "...",
"userName": "john_doe",
"email": "john@example.com",
"phone": "9876543210",
"address": "123 Main St",
"age": 28,
"userId": 1001,
"profilePicture": "https://res.cloudinary.com/demo/image/upload/...",
"timeOfLogin": "2024-03-05T..."
}
}{
"success": false,
"message": "Failed to upload profile picture"
}- Document size: ~2-5MB for a typical profile picture
- Storage inefficient
- Slow query performance
- Document size: ~100 bytes for URL + metadata
- 99% reduction in document size
- Faster queries
- Better scalability
- Reduced backup size
Ensure these are set in .env.local:
CLOUDINARY_CLOUD_NAME=your_cloud_name
CLOUDINARY_API_KEY=your_api_key
CLOUDINARY_API_SECRET=your_api_secret
-
app/api/user-profile/route.js - Main API endpoint
- Added Cloudinary integration
- Fixed profile picture handling for all roles
- Updated GET/PUT handlers
-
app/user/components/UserProfile.js - User profile component
- Added profile picture upload UI
- Added file validation
- Updated state management
The fix maintains backward compatibility:
- Existing profile pictures (if any base64 encoded) will still display
- New uploads use Cloudinary URLs
- Database schema unchanged
- API response structure unchanged
- Migration Script: Create a script to migrate existing base64 profile pictures to Cloudinary
- Batch Operations: Add batch profile picture upload for admins
- Image Optimization: Consider adding image optimization through Cloudinary transformations
- CDN Caching: Leverage Cloudinary's global CDN for better performance
- Profile Picture Cropping: Add UI for image cropping before upload
db.User.findOne({}, { profilePicture: 1 })
// Should return: { profilePicture: "https://res.cloudinary.com/..." }Look for messages like:
Profile picture uploaded to Cloudinary: https://...User profile updated: { userId: 1001, profilePictureUpdated: true }
| Issue | Cause | Solution |
|---|---|---|
| Profile picture not saving | Cloudinary credentials not set | Check .env.local file |
| File upload fails | File too large or wrong format | Check file size < 5MB, must be image |
| Picture not displaying | Old base64 data | Ensure frontend uses new profilePicture URL |
| 500 error on upload | Cloudinary API issue | Check internet connection, Cloudinary status |
Last Updated: March 5, 2026 Status: ✅ All Issues Fixed