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

8.1 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, 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 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, sortOrder
  • PATCH /comments/:commentId
    • JSON body: content, mentionUsernames

WebSocket auth

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
  • a thumbnail image is generated automatically if the client does not send thumbnailUrl

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

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.