AIRBNB
FRONTEND GUIDE FOR AI CODING AGENTS - PART 4 - Profile Management
This document is a part of a REST API guide for the airbnb project. It is designed for AI agents that will generate frontend code to consume the project’s backend.
This document includes information and api descriptions about building a profile page in the frontend using the auth service profile api calls. Avatar images are stored in the auth service’s database buckets — no external bucket service is needed for avatars.
The project has 1 auth service, 1 notification service, 1 BFF service, and 6 business services, plus other helper services such as bucket and realtime. In this document you will use the auth service (including its database bucket endpoints for avatar uploads).
Each service is a separate microservice application and listens for HTTP requests at different service URLs.
Services may be deployed to the preview server, staging server, or production server. Therefore, each service has 3 access URLs. The frontend application must support all deployment environments during development, and the user should be able to select the target API server on the home page.
Accessing the backend
Each backend service has its own URL for each deployment environment. Users may want to test the frontend in one of the three deployments—preview, staging, or production. Please ensure that the register and login pages include a deployment server selection option so that, as the frontend coding agent, you can set the base URL for all services.
The base URL of the application in each environment is as follows:
- Preview:
https://airbnb3.prw.mindbricks.com - Staging:
https://airbnb3-stage.mindbricks.co - Production:
https://airbnb3.mindbricks.co
For the auth service, service urls are as follows:
- Preview:
https://airbnb3.prw.mindbricks.com/auth-api - Staging:
https://airbnb3-stage.mindbricks.co/auth-api - Production:
https://airbnb3.mindbricks.co/auth-api
For each other service, the service URL will be given in the service sections.
Any request that requires login must include a valid token in the Bearer authorization header.
Avatar Storage (Database Buckets)
User avatars and tenant avatars are stored directly in the auth service database using database buckets (dbBuckets). This means avatar files are uploaded to and downloaded from the auth service itself — no external bucket service is needed.
The auth service provides these avatar buckets:
User Avatar Bucket
Upload: POST {authBaseUrl}/bucket/userAvatars/upload
Download by ID: GET {authBaseUrl}/bucket/userAvatars/download/{fileId}
Download by Key: GET {authBaseUrl}/bucket/userAvatars/download/key/{accessKey}
- Read access: Public (anyone can view avatars, no auth needed for download)
- Write access: Authenticated (any logged-in user can upload their own avatar)
- Allowed types: image/png, image/jpeg, image/webp, image/gif
- Max size: 5 MB
- Access key: Each uploaded file gets a 12-character random key for shareable links
Upload example (multipart/form-data):
const formData = new FormData();
formData.append('file', croppedImageBlob, 'avatar.png');
const response = await fetch(`${authBaseUrl}/bucket/userAvatars/upload`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
},
body: formData,
});
const result = await response.json();
// result.file.id — the file ID (use for download URL)
// result.file.accessKey — 12-char key for public sharing
// result.file.fileName, result.file.mimeType, result.file.fileSize
After uploading, update the user’s avatar field with the download URL:
const avatarUrl = `${authBaseUrl}/bucket/userAvatars/download/${result.file.id}`;
// OR use the access key for a shorter, shareable URL:
const avatarUrl = `${authBaseUrl}/bucket/userAvatars/download/key/${result.file.accessKey}`;
await updateProfile({ avatar: avatarUrl });
Displaying avatars: Since read access is public, avatar URLs can be used directly in <img> tags without any authentication token:
<img src={user.avatar} alt="Avatar" />
Listing and Deleting Avatars
The auth service also provides metadata APIs for each bucket (auto-generated):
| API | Method | Path | Description |
|---|---|---|---|
getUserAvatarsFile |
GET | /v1/userAvatarsFiles/:id |
Get file metadata (no binary) |
listUserAvatarsFiles |
GET | /v1/userAvatarsFiles |
List files with filtering |
deleteUserAvatarsFile |
DELETE | /v1/userAvatarsFiles/:id |
Delete file and its data |
Profile Page
Design a profile page to manage (view and edit) user information. The profile page should include an avatar upload component that uploads to the database bucket.
On the profile page, you will need 4 business APIs: getUser , updateProfile, updateUserPassword and archiveProfile. Do not rely on the /currentuser response for profile data, because it contains session information. The most recent user data is in the user database and should be accessed via the getUser business API.
The updateProfile, updateUserPassword and archiveProfile api can only be called by the users themselves. They are designed specific to the profile page.
Avatar upload workflow:
- User selects an image → crop with
react-easy-crop(install it, do not implement your own) - Convert cropped area to a Blob
- Upload to
POST {authBaseUrl}/bucket/userAvatars/uploadwith the access token - Get back the file metadata (id, accessKey)
- Construct the download URL:
{authBaseUrl}/bucket/userAvatars/download/key/{accessKey} - Call
updateProfile({ avatar: downloadUrl })to save it
Note that the user cannot change/update their email or roleId.
For password update you should make a separate block in the UI, so that user can enter old password, new password and confirm new password before calling the updateUserPassword.
Here are the 3 auth APIs—getUser , updateProfile and updateUserPassword— as follows:
You can access these APIs through the auth service base URL, {appUrl}/auth-api.
Get User API
This api is used by admin roles or the users themselves to get the user profile information.
Rest Route
The getUser API REST controller can be triggered via the following route:
/v1/users/:userId
Rest Request Parameters
The getUser api has got 1 regular request parameter
| Parameter | Type | Required | Population |
|---|---|---|---|
| userId | ID | true | request.params?.[“userId”] |
| userId : This id paremeter is used to query the required data object. |
REST Request To access the api you can use the REST controller with the path GET /v1/users/:userId
axios({
method: 'GET',
url: `/v1/users/${userId}`,
data: {
},
params: {
}
});
REST Response
{
"status": "OK",
"statusCode": "200",
"elapsedMs": 126,
"ssoTime": 120,
"source": "db",
"cacheKey": "hexCode",
"userId": "ID",
"sessionId": "ID",
"requestId": "ID",
"dataName": "user",
"method": "GET",
"action": "get",
"appVersion": "Version",
"rowCount": 1,
"user": {
"id": "ID",
"email": "String",
"password": "String",
"fullname": "String",
"avatar": "String",
"roleId": "String",
"emailVerified": "Boolean",
"preferredLanguage": "String",
"bio": "Text",
"isActive": true,
"recordVersion": "Integer",
"createdAt": "Date",
"updatedAt": "Date",
"_owner": "ID"
}
}
Update Profile API
This route is used by users to update their profiles.
Rest Route
The updateProfile API REST controller can be triggered via the following route:
/v1/profile/:userId
Rest Request Parameters
The updateProfile api has got 5 regular request parameters
| Parameter | Type | Required | Population |
|---|---|---|---|
| userId | ID | true | request.params?.[“userId”] |
| fullname | String | false | request.body?.[“fullname”] |
| avatar | String | false | request.body?.[“avatar”] |
| preferredLanguage | String | false | request.body?.[“preferredLanguage”] |
| bio | Text | false | request.body?.[“bio”] |
| userId : This id paremeter is used to select the required data object that will be updated | |||
| fullname : A string value to represent the fullname of the user | |||
| avatar : The avatar url of the user. A random avatar will be generated if not provided | |||
| preferredLanguage : User’s preferred language for the application interface | |||
| bio : User’s biography or profile description |
REST Request To access the api you can use the REST controller with the path PATCH /v1/profile/:userId
axios({
method: 'PATCH',
url: `/v1/profile/${userId}`,
data: {
fullname:"String",
avatar:"String",
preferredLanguage:"String",
bio:"Text",
},
params: {
}
});
REST Response
{
"status": "OK",
"statusCode": "200",
"elapsedMs": 126,
"ssoTime": 120,
"source": "db",
"cacheKey": "hexCode",
"userId": "ID",
"sessionId": "ID",
"requestId": "ID",
"dataName": "user",
"method": "PATCH",
"action": "update",
"appVersion": "Version",
"rowCount": 1,
"user": {
"id": "ID",
"email": "String",
"password": "String",
"fullname": "String",
"avatar": "String",
"roleId": "String",
"emailVerified": "Boolean",
"preferredLanguage": "String",
"bio": "Text",
"isActive": true,
"recordVersion": "Integer",
"createdAt": "Date",
"updatedAt": "Date",
"_owner": "ID"
}
}
Update Userpassword API
This route is used to update the password of users in the profile page by users themselves
Rest Route
The updateUserPassword API REST controller can be triggered via the following route:
/v1/userpassword/:userId
Rest Request Parameters
The updateUserPassword api has got 3 regular request parameters
| Parameter | Type | Required | Population |
|---|---|---|---|
| userId | ID | true | request.params?.[“userId”] |
| oldPassword | String | true | request.body?.[“oldPassword”] |
| newPassword | String | true | request.body?.[“newPassword”] |
| userId : This id paremeter is used to select the required data object that will be updated | |||
| oldPassword : The old password of the user that will be overridden bu the new one. Send for double check. | |||
| newPassword : The new password of the user to be updated |
REST Request To access the api you can use the REST controller with the path PATCH /v1/userpassword/:userId
axios({
method: 'PATCH',
url: `/v1/userpassword/${userId}`,
data: {
oldPassword:"String",
newPassword:"String",
},
params: {
}
});
REST Response
{
"status": "OK",
"statusCode": "200",
"elapsedMs": 126,
"ssoTime": 120,
"source": "db",
"cacheKey": "hexCode",
"userId": "ID",
"sessionId": "ID",
"requestId": "ID",
"dataName": "user",
"method": "PATCH",
"action": "update",
"appVersion": "Version",
"rowCount": 1,
"user": {
"id": "ID",
"email": "String",
"password": "String",
"fullname": "String",
"avatar": "String",
"roleId": "String",
"emailVerified": "Boolean",
"preferredLanguage": "String",
"bio": "Text",
"isActive": true,
"recordVersion": "Integer",
"createdAt": "Date",
"updatedAt": "Date",
"_owner": "ID"
}
}
Archiving A Profile
A user may want to archive their profile. So the profile page should include an archive section for the users to archive their accounts. When an account is archived, it is marked as archived and an aarchiveDate is atteched to the profile. All user data is kept in the database for 1 month after user archived. If user tries to login or register with the same email, the account will be activated again. But if no login or register occures in 1 month after archiving, the profile and its related data will be deleted permanenetly. So in the profile page,
- The arcihve options should be accepted after user writes a text like (“ARCHİVE MY ACCOUNT”) to a confirmation dialog, so that frontend UX can ensure this is not an unconscious request.
- The user should be warned about the process, that his account will be available for a restore for 1 month.
The archive api, can only be called by the users themselves and its used as follows.
Archive Profile API
This api is used by users to archive their profiles.
Rest Route
The archiveProfile API REST controller can be triggered via the following route:
/v1/archiveprofile/:userId
Rest Request Parameters
The archiveProfile api has got 1 regular request parameter
| Parameter | Type | Required | Population |
|---|---|---|---|
| userId | ID | true | request.params?.[“userId”] |
| userId : This id paremeter is used to select the required data object that will be deleted |
REST Request To access the api you can use the REST controller with the path DELETE /v1/archiveprofile/:userId
axios({
method: 'DELETE',
url: `/v1/archiveprofile/${userId}`,
data: {
},
params: {
}
});
REST Response
{
"status": "OK",
"statusCode": "200",
"elapsedMs": 126,
"ssoTime": 120,
"source": "db",
"cacheKey": "hexCode",
"userId": "ID",
"sessionId": "ID",
"requestId": "ID",
"dataName": "user",
"method": "DELETE",
"action": "delete",
"appVersion": "Version",
"rowCount": 1,
"user": {
"id": "ID",
"email": "String",
"password": "String",
"fullname": "String",
"avatar": "String",
"roleId": "String",
"emailVerified": "Boolean",
"preferredLanguage": "String",
"bio": "Text",
"isActive": false,
"recordVersion": "Integer",
"createdAt": "Date",
"updatedAt": "Date",
"_owner": "ID"
}
}
After you complete this step, please ensure you have not made the following common mistakes:
- Avatar uploads go to the auth service’s database bucket endpoints (
/bucket/userAvatars/upload), not to an external bucket service. Use the sameaccessToken(Bearer header) for both auth APIs and avatar bucket uploads — no bucket-specific tokens are needed. - Note that any api call to the application backend is based on a service base url, in this prompt all auth apis (including avatar bucket endpoints) should be called by the auth service base url.
- On the profile page, fetch the latest user data from the service using
getUser. The/currentuserAPI is session-stored data; the latest data is in the database. - When you upload the avatar image on the profile page, use the returned download URL as the user’s
avatarproperty and update the user record when the Save button is clicked.
After this prompt, the user may give you new instructions to update your first output or provide subsequent prompts about the project.