7.4 KiB
Frontend Integration
Network setup
When testing from a phone or another device on the same LAN:
- Set
HOST=0.0.0.0 - Set
PUBLIC_BASE_URLto the machine IP, notlocalhost - Add frontend origins to
CORS_ORIGINS - Keep
GOOGLE_CALLBACK_URLon the same reachable host if Google auth is used
Example:
HOST=0.0.0.0
PUBLIC_BASE_URL=http://192.168.1.12:4000
CORS_ORIGINS=http://192.168.1.12:3000,http://192.168.1.12:5173
GOOGLE_CALLBACK_URL=http://192.168.1.12:4000/api/v1/auth/google/callback
With PUBLIC_BASE_URL configured, file fields such as avatar, coverImage, imageUrls, videoUrl, audioUrl, thumbnailUrl, mediaUrl, and marketplace images are returned as absolute URLs.
Pagination contract
List endpoints now keep the legacy fields and also return a unified pagination object.
Example:
{
"items": [],
"count": 0,
"page": 1,
"limit": 20,
"total": 0,
"totalPages": 1,
"nextCursor": null,
"pagination": {
"mode": "offset",
"page": 1,
"limit": 20,
"count": 0,
"total": 0,
"totalPages": 1,
"hasNextPage": false,
"hasPreviousPage": false,
"nextPage": null,
"previousPage": null,
"currentCursor": null,
"nextCursor": null
}
}
Notes:
- Offset endpoints use
pageandlimit - Cursor-aware endpoints also return
nextCursor - Existing clients can keep reading the old top-level fields
sortOrder=asc|descis available on paginated endpoints
Filter and sorting contract
Boolean query filters are parsed consistently now. Send:
?isActive=true?isActive=false?read=true?read=false?followingOnly=true
Common conventions:
page,limit,sortOrdersortOrderdefaults todescsortByis supported on selected endpoints with endpoint-specific allowed values
Supported filters:
GET /marketplace/homelistingsLimit,instrumentsLimit,repairShopsLimit,onlyActive
GET /usersq,isVerified,musicRole,experienceLevel,isPrivate,hasAvatar,sortBysortBy:createdAt,name,username,followersCount,postsCount
GET /users/discoverq,musicRole,experienceLevel,hasAvatarOnly,includeRoleBuckets,sortBy,sortOrder
GET /users/:id/profile-overview- returns
stats,contentCounts,tabs, andviewerState
- returns
GET /posts/user/:userIdvisibility,postType,q,hashtag,sortBysortBy:createdAt,updatedAt,likesCount,commentsCount,savesCount,shareCount,viewCount,playCount
GET /posts/reelsvisibility,authorId,q,sortBy
GET /marketplace/listingsq,minPrice,maxPrice,isActive,listingCategory,condition,instrumentType,sortBylistingCategory:musical_instrument,accessory,audio_gear,sheet_music,other
GET /marketplace/instrumentsq,minPrice,maxPrice,isActive,condition,instrumentType,sortBy- this route is now a musical-instruments-only view of marketplace listings
sortBy:createdAt,updatedAt,price,title
GET /marketplace/repair-shopsq,isActive,sortBysortBy:createdAt,updatedAt,name
GET /notificationsread,type,resourceType,sortOrder
GET /comments/post/:postIdpage,limit,sortOrder
PATCH /comments/:commentId- JSON body:
content,mentionUsernames
- JSON body:
WebSocket auth
Both namespaces accept the JWT access token in one of these places:
auth.tokenAuthorizationheader asBearer <token>
Chat namespace
Namespace: /chat
Client emits:
join_conversation- payload:
{ "conversationId": "..." }
- payload:
send_message- payload matches
SendMessageDto
- payload matches
typing- payload:
{ "conversationId": "...", "isTyping": true }
- payload:
mark_seen- payload:
{ "messageId": "...", "conversationId": "..." }
- payload:
Server emits:
presence- payload:
{ "userId": "...", "online": true }
- payload:
joined_conversation- payload:
{ "conversationId": "..." }
- payload:
new_message- payload: message object
typing- payload:
{ "conversationId": "...", "userId": "...", "isTyping": true }
- payload:
message_seen- payload:
{ "messageId": "...", "userId": "..." }
- payload:
Notifications namespace
Namespace: /notifications
Server emits:
notification_created- payload: notification object
notifications_unread_count- payload:
{ "unreadCount": 3 }
- payload:
Notification types currently used:
likecommentfollowmessagesavesharemention
Mentions
Posts and comments support:
taggedUserIds: official tagged users by Mongo idmentionUsernames: usernames such as["rami_sabry"]
The backend also extracts @username from content automatically and emits mention notifications for matched users.
Posts Upload Contract
Post creation and updates now require multipart/form-data for all post payloads, including text-only posts and posts that use external media links.
POST /postsPATCH /posts/:postIdPOST /posts/reels
Send media uploads as files:
imageFilesvideoFileaudioFile
Send link-based fields as text fields inside the same form-data payload:
imageUrlsvideoUrlaudioUrlthumbnailUrl
Array fields may be sent either as repeated form keys or JSON text:
taggedUserIdsmentionUsernamesimageUrlswaveformPeaks
Marketplace split
Marketplace is now separated from musical instruments at the API contract level:
GET /marketplace/listings- general sale listings across all listing categories
GET /marketplace/instruments- only musical instruments
GET /marketplace/repair-shops- service providers and maintenance shops
GET /marketplace/home- frontend-friendly grouped payload with
categories,summary,filters.listingCategories,featuredShops, andsections
- frontend-friendly grouped payload with
Admin endpoints follow the same split:
POST /marketplace/admin/listingsGET /marketplace/admin/listings/mePATCH /marketplace/admin/listings/:idDELETE /marketplace/admin/listings/:id
The older /marketplace/admin/instruments* routes still exist and always force listingCategory=musical_instrument for backward compatibility.
Marketplace shop ownership rule:
- each admin can own one repair-shop / marketplace shop record only
- if the admin already created one, the frontend should call update endpoints instead of create
Listing responses now also include:
shop{ adminId, name, username, avatar }
storeName- direct shortcut for list cards
conditionnew,like_new,used,refurbished
instrumentType- free-text type such as
oud,piano, orviolin
- free-text type such as
Search on marketplace listings now matches:
- listing title
- listing description
- instrument type
- shop name
Talent discovery
The talents screen can now be built from:
GET /users/discover- paginated talent cards
roleBucketscounts for tabs such as instrumentalists, singers, producers, and lyricists
GET /users/:id/profile-overview- summary for the profile header and tab counts
profile-overview returns:
stats.followersCountstats.followingCountstats.postsCountstats.collaborationsCountcontentCounts.reelscontentCounts.audiocontentCounts.otherviewerState.following
Smoke / e2e
Run:
npm run test:e2e
The smoke suite covers health, auth verification, profile setup, image upload, post creation, feed retrieval, notifications, and comment mentions.