YeboShops Messaging System Documentation
Overview
YeboShops implements a two-tier messaging system designed for marketplace/classified interactions. Similar to Facebook Pages, users can message shops (not other users directly), and shop owners manage these conversations through their shop identity.
Architecture
Core Principles
- Shop-Centric Communication: All messages flow through shops, never directly between users
- Dual Identity Management: Shop owners can act as themselves or as their shop
- Notification Routing: Messages to shops trigger notifications to shop owners
- Message Attribution: Clear distinction between user messages and shop responses
Data Models
Chat Model
interface IChat {
participants: string (UUID)[]; // [userId, shopOwnerId]
shop: string (UUID); // Required - the shop being messaged
lastProduct?: string (UUID); // Optional - last discussed product
createdAt: Date;
updatedAt: Date;
}Message Model
interface IMessage {
chatId: string (UUID);
senderId: string (UUID); // User ID or Shop ID
senderType: 'User' | 'Shop';
content: string;
productContext?: IProductContext;
attachments?: IMessageAttachment[];
replyToMessageId?: string (UUID);
read: boolean;
readAt?: Date;
createdAt: Date;
}Notification Model
Messages sent to shops create notifications for shop owners:
{
user: string (UUID); // Shop owner's user ID
type: 'chat';
title: string; // "New message from [username]"
message: string; // Message preview (50 chars)
data: {
chatId: string;
}
}Message Flow
1. User Initiates Conversation with Shop
sequenceDiagram
participant User
participant API
participant Shop
participant ShopOwner
User->>API: POST /chats
Note right of User: {shopId, content, productId?}
API->>API: Create/Find Chat
API->>API: Create Message (senderType: 'User')
API->>Shop: Associate message with shop
API->>ShopOwner: Send notification
API-->>User: Return message & chatIdEndpoint: POST /chats/messages
{
"shopId": "shop_123",
"content": "Is this item still available?",
"productId": "product_456" // Optional
}2. Shop Owner Views Messages
sequenceDiagram
participant ShopOwner
participant API
participant Database
ShopOwner->>API: GET /chats/user/:userId
API->>Database: Find chats where user participates
API->>Database: Find chats for user's shops
Database-->>API: Return combined chats
API->>API: Mark with isShopOwner flag
API-->>ShopOwner: Return enriched chatsEndpoint: GET /chats/user/:userId or GET /chats/with-unread-counts
Response includes:
- Chats where user is a participant
- Chats for shops owned by the user
isShopOwner: trueflag for shop-owned chats
3. Shop Owner Replies to Message
sequenceDiagram
participant ShopOwner
participant API
participant User
ShopOwner->>API: POST /chats
Note right of ShopOwner: {chatId, content}
API->>API: Check if sender owns shop
API->>API: Create Message (senderType: 'Shop')
API->>API: Set senderId to shop ID
API-->>ShopOwner: Return message
API->>User: Message appears from shopEndpoint: POST /chats
{
"chatId": "chat_789",
"content": "Yes, this item is available!"
}API Endpoints
Core Messaging Endpoints
Send Message
POST /chats
Authorization: Bearer {token}
{
"shopId": "string", // Required for new chat
"chatId": "string", // Required for existing chat
"content": "string", // Required
"productId": "string", // Optional
"replyToMessageId": "string" // Optional
}Alternative Shop Message Route
POST /chats/shop/:shopId
Authorization: Bearer {token}
{
"content": "string",
"productId": "string",
"replyToMessageId": "string"
}Get User's Chats
GET /chats/user/:userId
Authorization: Bearer {token}Returns all chats including those for shops owned by the user.
Get Enhanced Chats with Unread Counts
GET /chats/with-unread-counts
Authorization: Bearer {token}
Query params:
- limit: number (1-50, default: 20)
- before: ISO timestamp (for pagination)
- includeTotalCount: booleanGet Messages from Chat
GET /chats/:chatId/messages
Authorization: Bearer {token}
Query params:
- limit: number (1-100, default: 30)
- before: ISO timestamp (pagination cursor)
- after: ISO timestamp (reverse pagination)Check if Chat Exists
POST /chats/check-exists
Authorization: Bearer {token}
{
"userId": "string",
"shopId": "string"
}Or use the GET alternative:
GET /chats/shop/:shopId/check-exists
Authorization: Bearer {token}Read Receipt Management
Mark Messages as Read
POST /chats/:chatId/read
Authorization: Bearer {token}Get Unread Count for Chat
GET /chats/:chatId/unread-count
Authorization: Bearer {token}Get All Unread Counts
GET /chats/unread-counts
Authorization: Bearer {token}Additional Features
Get Last Product from Chat
GET /chats/:chatId/last-product
Authorization: Bearer {token}Get Chat Details
GET /chats/:chatId
Authorization: Bearer {token}Business Rules
Message Creation Rules
Chat Initialization
- Only users can initiate chats with shops
- Shop owners cannot start conversations (must wait for user contact)
- Each user-shop pair has only one chat
Sender Identification
- Regular users:
senderType: 'User',senderId: userId - Shop owners replying:
senderType: 'Shop',senderId: shopId - System automatically detects sender type based on chat ownership
- Regular users:
Validation Rules
- Cannot message yourself
- Cannot message non-existent shops
- Must be a chat participant to send messages
- Either
chatIdorshopIdrequired (not both)
Notification Rules
Recipient Routing
- Messages to shops → Notifications to shop owner's user account
- No notifications for own messages
- De-duplication within 5-minute window
Notification Content
- Title: "New message from [username]"
- Body: First 50 characters of message
- Data: Includes chatId for navigation
Chat Retrieval Rules
Visibility
- Users see chats where they are participants
- Shop owners additionally see all chats for their shops
- Chats marked with
isShopOwnerflag when applicable
Ordering
- Chats sorted by most recent activity
- Messages sorted chronologically within chats
Security Considerations
Authentication & Authorization
- All endpoints require authentication via Bearer token
- Users can only access their own chats
- Shop owners have elevated access to shop-related chats
Data Privacy
- Messages are private between user and shop
- No public message visibility
- Read receipts only visible to participants
Rate Limiting Recommendations
- Message sending: 30 messages/minute per user
- Chat creation: 10 new chats/hour per user
- File uploads: 50MB max per attachment
Implementation Notes
Product Context
Messages can include product context when discussing specific items:
interface IProductContext {
productId: string;
title: string;
image: string;
mediaType: 'image' | 'video';
price: string;
url: string;
}Attachment Support
Messages support image and video attachments:
interface IMessageAttachment {
type: 'image' | 'video';
url: string;
key: string; // R2 storage key
filename: string;
size?: number;
mimeType?: string;
}Pagination
The system uses cursor-based pagination with ISO timestamps:
before: Get older messagesafter: Get newer messages- Returns
nextCursor,prevCursor,hasMore,hasPrevious
Real-time Considerations
While not currently implemented, the system is designed to support:
- WebSocket connections for real-time messaging
- Push notifications for mobile apps
- Online/offline status tracking
Error Handling
Common error responses:
| Error | Status Code | Message |
|---|---|---|
| Missing shopId/chatId | 400 | "Either chatId or shopId must be provided" |
| Shop not found | 404 | "Shop not found" |
| Not a participant | 403 | "User is not a participant in this chat" |
| Self-messaging | 400 | "Shop owners cannot initiate conversations" |
| Invalid string (UUID) | 400 | "Invalid ID format" |
Testing Checklist
- [ ] User can message a shop
- [ ] Shop owner receives notification
- [ ] Shop owner sees chat in their list
- [ ] Shop owner can reply as shop
- [ ] User sees shop's reply
- [ ] Cannot message users directly
- [ ] Cannot self-message
- [ ] Read receipts work correctly
- [ ] Unread counts are accurate
- [ ] Pagination works in both directions
- [ ] Product context is preserved
- [ ] Attachments upload successfully
Migration Notes
For existing systems migrating to this architecture:
- Existing User-to-User Chats: Should be deprecated or migrated to shop-based chats
- Notification System: Update to route through user IDs, not shop IDs
- Frontend Updates: Ensure UI distinguishes between user and shop messages
- Permission System: Verify shop owners have proper access to their shop's chats
Support & Maintenance
Monitoring Points
- Message delivery success rate
- Notification delivery rate
- Average response time
- Chat creation rate
- Unread message accumulation
Common Issues & Solutions
Issue: Shop owner not receiving notifications
- Check shop ownership in database
- Verify notification service is using owner's userId
- Check notification de-duplication window
Issue: Messages appearing as user instead of shop
- Verify shop ownership
- Check senderType logic in message creation
- Ensure chatId is provided for replies
Issue: Missing chats for shop owner
- Verify shop ownership records
- Check query includes shop-owned chats
- Ensure proper indexing on shop field