الملفات
back_end_oudelaa/docs/FRONTEND_INTEGRATION.md

13 KiB

Frontend Integration

Network setup

When testing from a phone or another device on the same LAN:

  1. Set HOST=0.0.0.0
  2. Set PUBLIC_BASE_URL to the machine IP, not localhost
  3. Add frontend origins to CORS_ORIGINS
  4. Keep GOOGLE_CALLBACK_URL on 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, imageVariants, videoUrl, hlsUrl, audioUrl, thumbnailUrl, thumbnailVariants, 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 page and limit
  • Cursor-aware endpoints also return nextCursor
  • Existing clients can keep reading the old top-level fields
  • sortOrder=asc|desc is 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, sortOrder
  • sortOrder defaults to desc
  • sortBy is supported on selected endpoints with endpoint-specific allowed values

Supported filters:

  • GET /feed/me
    • defaults to followed accounts and the viewer's own posts
    • use followingOnly=false to widen the home feed to public discovery posts
    • preferredPostType, followingOnly, radiusKm, includeSuggestions, suggestionInterval
  • GET /marketplace/home
    • listingsLimit, instrumentsLimit, repairShopsLimit, onlyActive
  • GET /users
    • q, isVerified, musicRole, experienceLevel, isPrivate, hasAvatar, sortBy
    • sortBy: createdAt, name, username, followersCount, postsCount
  • GET /users/discover
    • q, musicRole, experienceLevel, hasAvatarOnly, includeRoleBuckets, sortBy, sortOrder
  • GET /users/:id/profile-overview
    • returns stats, contentCounts, tabs, and viewerState
  • GET /posts/user/:userId
    • visibility, postType, q, hashtag, sortBy
    • sortBy: createdAt, updatedAt, likesCount, commentsCount, savesCount, shareCount, viewCount, playCount
  • GET /posts/reels
    • visibility, authorId, q, sortBy
  • GET /marketplace/listings
    • q, minPrice, maxPrice, isActive, listingCategory, condition, instrumentType, sortBy
    • listingCategory: musical_instrument, accessory, audio_gear, sheet_music, other
  • GET /marketplace/instruments
    • q, 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-shops
    • q, isActive, sortBy
    • sortBy: createdAt, updatedAt, name
  • GET /notifications
    • read, type, resourceType, sortOrder
  • GET /comments/post/:postId
    • page, limit, sortBy, sortOrder
    • sortBy: createdAt, top
  • POST /comments/:commentId/replies
    • JSON body: content
    • the route commentId is the parent comment; clients do not send postId
  • GET /comments/:commentId/replies
    • page, limit, sortBy, sortOrder
    • sortBy: createdAt, top
  • PATCH /comments/:commentId
    • JSON body: content, mentionUsernames

Comment list items include Instagram-like UI fields:

  • repliesCount
  • repliesPreview
  • likesCount
  • likedByMe
  • canEdit
  • canDelete
  • replyToUser

WebSocket auth

Social upgrades

Reposts and quote posts

  • POST /posts/:postId/repost
    • body { "content": "" } creates a plain repost
    • body { "content": "My take" } creates a quote post
    • repost items expose repostOfPostId; quote items expose quoteOfPostId

Reactions

Existing likes endpoints now accept reactionType:

  • like
  • love
  • haha
  • wow
  • sad
  • angry

Example:

{
  "targetId": "...",
  "targetType": "post",
  "reactionType": "love"
}

GET /likes/status/:targetType/:targetId returns reactionType and reactionSummary.

Private follow requests

When targetUser.isPrivate=true, POST /follows/toggle creates a pending request instead of following immediately.

  • GET /follows/requests
  • PATCH /follows/requests/:requestId/approve
  • PATCH /follows/requests/:requestId/reject

GET /follows/status/:targetUserId returns requested.

Reports

  • POST /reports
    • targetType: user, post, comment, listing, repair_shop
    • targetId, reason, details
  • GET /reports/me
  • GET /reports/superadmin
  • PATCH /reports/superadmin/:reportId/status

Blocks

Global block endpoints:

  • POST /blocks/:targetUserId
  • PATCH /blocks/:targetUserId/unblock
  • GET /blocks/status/:targetUserId

Blocked users are excluded from feed/trending/explore visibility.

Explore

  • GET /feed/explore
    • public discovery feed using the trending ranking path
    • respects global block visibility

Both namespaces accept the JWT access token in one of these places:

  • auth.token
  • Authorization header as Bearer <token>

Chat namespace

Namespace: /chat

Client emits:

  • join_conversation
    • payload: { "conversationId": "..." }
  • send_message
    • payload matches SendMessageDto
  • typing
    • payload: { "conversationId": "...", "isTyping": true }
  • mark_seen
    • payload: { "messageId": "...", "conversationId": "..." }

Server emits:

  • presence
    • payload: { "userId": "...", "online": true }
  • joined_conversation
    • payload: { "conversationId": "..." }
  • new_message
    • payload: message object
  • typing
    • payload: { "conversationId": "...", "userId": "...", "isTyping": true }
  • message_seen
    • payload: { "messageId": "...", "userId": "..." }

Notifications namespace

Namespace: /notifications

Server emits:

  • notification_created
    • payload: notification object
  • notifications_unread_count
    • payload: { "unreadCount": 3 }

Notification types currently used:

  • like
  • comment
  • follow
  • message
  • save
  • share
  • mention

Mentions

Posts and comments support:

  • taggedUserIds: official tagged users by Mongo id
  • mentionUsernames: 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 /posts
  • PATCH /posts/:postId
  • POST /posts/reels

Send media uploads as files:

  • imageFiles
  • videoFile
  • audioFile

Send link-based fields as text fields inside the same form-data payload:

  • imageUrls
  • videoUrl
  • audioUrl
  • thumbnailUrl

Array fields may be sent either as repeated form keys or JSON text:

  • taggedUserIds
  • mentionUsernames
  • imageUrls
  • waveformPeaks

Video optimization

When VIDEO_PROCESSING_ENABLED=true and ffmpeg is available on the server:

  • uploaded post/reel videos are converted to optimized mp4
  • +faststart is applied so playback begins faster on mobile/web
  • uploaded post/reel videos also produce an HLS playlist at hlsUrl when VIDEO_PROCESSING_GENERATE_HLS=true
  • when ffprobe is available, hlsUrl points to a master playlist with multiple renditions so HLS players can downgrade quality automatically on weak networks
  • local storage responses serve mp4, m3u8, m4s, and ts files with explicit media Content-Type headers and Accept-Ranges: bytes
  • a thumbnail image is generated automatically if the client does not send thumbnailUrl
  • generated thumbnails also expose thumbnailVariants.lowUrl, thumbnailVariants.mediumUrl, thumbnailVariants.highUrl, and thumbnailVariants.originalUrl

If ffmpeg is not installed or video processing is disabled, uploads still work and the original video file is stored as-is.

Recommended client behavior:

  • use hlsUrl first when present for adaptive/streaming playback
  • fall back to videoUrl for progressive mp4 playback
  • for poster frames on weak networks, prefer thumbnailVariants.lowUrl or thumbnailVariants.mediumUrl

Audio and image delivery

Managed uploads are stored under stable UUID-based paths, so local storage responses now send cache-friendly headers:

  • images (jpg, jpeg, png, webp, gif) are served with explicit Content-Type and long-lived immutable Cache-Control
  • audio (mp3, wav, m4a, aac, ogg) is served with explicit Content-Type, long-lived immutable Cache-Control, and Accept-Ranges: bytes
  • uploaded post images are normalized into responsive variants and posts now include imageVariants[]

Recommended client behavior:

  • for audio, stream audioUrl directly and allow byte-range playback/resume
  • imageUrls now default to feed-friendly optimized images for backward compatibility
  • on weak networks, prefer imageVariants[index].lowUrl
  • on normal networks, use imageUrls[index] or imageVariants[index].mediumUrl
  • on detail screens or zoom views, use imageVariants[index].highUrl or imageVariants[index].originalUrl

Instagram-style social controls

Posts now support:

  • carousel metadata through imageItems[] with url, caption, altText, and order
  • collaboratorIds[] on create/update
  • profile pinning through PATCH /posts/:postId/pin-profile and /unpin-profile
  • archive/restore through PATCH /posts/:postId/archive and /restore-archive
  • per-post comment settings through PATCH /posts/:postId/comment-settings

Comment settings:

  • commentsDisabled
  • commentsFollowersOnly
  • commentFilterKeywords[]

Comments now support:

  • PATCH /comments/:commentId/pin
  • PATCH /comments/:commentId/unpin
  • hidden offensive/filter matches via hiddenByFilter

Chat now supports:

  • message media upload through POST /chat/messages/upload
  • replies with replyToMessageId
  • reactions through PATCH /chat/messages/:messageId/reaction
  • delete-for-me through PATCH /chat/messages/:messageId/delete-for-me

Reports now require fixed reason values:

  • spam, harassment, hate_speech, nudity, violence, scam, intellectual_property, self_harm, other

When a post/comment reaches multiple open reports, the backend can automatically flag it for moderation. User reports can include blockTarget: true to block the reported user immediately.

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, and sections

Admin endpoints follow the same split:

  • POST /marketplace/admin/listings
  • GET /marketplace/admin/listings/me
  • PATCH /marketplace/admin/listings/:id
  • DELETE /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
  • condition
    • new, like_new, used, refurbished
  • instrumentType
    • free-text type such as oud, piano, or violin

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
    • roleBuckets counts 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.followersCount
  • stats.followingCount
  • stats.postsCount
  • stats.collaborationsCount
  • contentCounts.reels
  • contentCounts.audio
  • contentCounts.other
  • viewerState.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.