# Messaging System Implementation This document describes the messaging system that enables threaded conversations between different platform participants. ## Overview The messaging system supports three communication channels: 1. **Admin <-> Store**: Platform administrators communicate with store users 2. **Store <-> Customer**: Stores communicate with their customers 3. **Admin <-> Customer**: Platform administrators communicate with customers ## Architecture ### Database Models Located in `models/database/message.py`: | Model | Description | |-------|-------------| | `Conversation` | Threaded conversation container with subject, type, and status | | `ConversationParticipant` | Links participants to conversations with unread tracking | | `Message` | Individual messages within a conversation | | `MessageAttachment` | File attachments for messages | ### Enums | Enum | Values | Description | |------|--------|-------------| | `ConversationType` | `admin_store`, `store_customer`, `admin_customer` | Defines conversation channel | | `ParticipantType` | `admin`, `store`, `customer` | Type of participant | ### Polymorphic Participants The system uses polymorphic relationships via `participant_type` + `participant_id`: - `admin` and `store` types reference `users.id` - `customer` type references `customers.id` ### Multi-Tenant Isolation Conversations involving customers include a `store_id` to ensure proper data isolation. Store users can only see conversations within their store context. ## Services ### MessagingService (`app/services/messaging_service.py`) Core business logic for conversations and messages: | Method | Description | |--------|-------------| | `create_conversation()` | Create a new conversation with participants | | `get_conversation()` | Get conversation with access validation | | `list_conversations()` | Paginated list with filters | | `send_message()` | Send message with automatic unread updates | | `mark_conversation_read()` | Mark all messages read for participant | | `get_unread_count()` | Get total unread count for header badge | | `close_conversation()` | Close a conversation thread | | `reopen_conversation()` | Reopen a closed conversation | ### MessageAttachmentService (`app/services/message_attachment_service.py`) File upload handling: | Method | Description | |--------|-------------| | `validate_and_store()` | Validate file type/size and store to disk | | `get_max_file_size_bytes()` | Get limit from platform settings | | `delete_attachment()` | Remove files from storage | **Allowed file types:** - Images: JPEG, PNG, GIF, WebP - Documents: PDF, Office documents - Archives: ZIP - Text: Plain text, CSV **Storage path pattern:** `uploads/messages/YYYY/MM/conversation_id/uuid.ext` ## API Endpoints ### Admin API (`/api/v1/admin/messages`) | Endpoint | Method | Description | |----------|--------|-------------| | `/messages` | GET | List conversations | | `/messages` | POST | Create conversation | | `/messages/unread-count` | GET | Get unread badge count | | `/messages/recipients` | GET | Get available recipients | | `/messages/{id}` | GET | Get conversation detail | | `/messages/{id}/messages` | POST | Send message (with attachments) | | `/messages/{id}/close` | POST | Close conversation | | `/messages/{id}/reopen` | POST | Reopen conversation | | `/messages/{id}/read` | PUT | Mark as read | | `/messages/{id}/preferences` | PUT | Update notification preferences | ### Store API (`/api/v1/store/messages`) Same structure as admin, but with store context filtering. Stores can only: - See their own store_customer and admin_store conversations - Create store_customer conversations with their customers - Not initiate admin_store conversations (admins initiate those) ## Frontend ### Admin Interface - **Template:** `app/templates/admin/messages.html` - **JavaScript:** `static/admin/js/messages.js` Features: - Split-panel conversation list + message thread - Filters by type (stores/customers) and status (open/closed) - Compose modal for new conversations - File attachment support - 30-second polling for new messages - Header badge with unread count ### Store Interface - **Template:** `app/templates/store/messages.html` - **JavaScript:** `static/store/js/messages.js` Similar to admin but with store-specific: - Only store_customer and admin_store channels - Compose modal for customer conversations only ## Pydantic Schemas Located in `models/schema/message.py`: - `ConversationCreate` - Create request - `ConversationSummary` - List item with unread count - `ConversationDetailResponse` - Full thread with messages - `ConversationListResponse` - Paginated list - `MessageResponse` - Single message with attachments - `AttachmentResponse` - File metadata with download URL - `UnreadCountResponse` - For header badge ## Configuration ### Platform Setting The attachment size limit is configurable via platform settings: - **Key:** `message_attachment_max_size_mb` - **Default:** 10 - **Category:** messaging ## Shop (Customer) Interface ### API Endpoints (`/api/v1/shop/messages`) | Endpoint | Method | Description | |----------|--------|-------------| | `/messages` | GET | List customer's conversations | | `/messages/unread-count` | GET | Get unread badge count | | `/messages/{id}` | GET | Get conversation detail | | `/messages/{id}/messages` | POST | Send reply message | | `/messages/{id}/read` | PUT | Mark as read | | `/messages/{id}/attachments/{att_id}` | GET | Download attachment | ### Frontend - **Template:** `app/templates/shop/account/messages.html` - **Page Route:** `/shop/account/messages` and `/shop/account/messages/{conversation_id}` Features: - Conversation list with unread badges - Filter by status (open/closed) - Thread view with message history - Reply form with file attachments - 30-second polling for new messages - Link from account dashboard with unread count ### Limitations Customers can only: - View their `store_customer` conversations - Reply to existing conversations (cannot initiate) - Cannot close conversations --- ## Future Enhancements ### Email Notifications (Requires Email Infrastructure) The messaging system is designed to support email notifications, but requires email infrastructure to be implemented first: **Prerequisites:** - SMTP configuration in settings (host, port, username, password) - Email service (`app/services/email_service.py`) - Email templates (`app/templates/emails/`) - Background task queue for async sending **Planned Implementation:** 1. **MessageNotificationService** (`app/services/message_notification_service.py`) - `notify_new_message()` - Send email to participants on new message - Respect per-conversation `email_notifications` preference - Include message preview and reply link 2. **Email Template** (`app/templates/emails/new_message.html`) - Subject: "New message: {conversation_subject}" - Body: Sender name, message preview, link to reply 3. **Integration Points:** - Call `notify_new_message()` from `messaging_service.send_message()` - Skip notification for sender (only notify other participants) - Rate limit to prevent spam on rapid message exchanges **Database Support:** The `email_notifications` field on `ConversationParticipant` is already in place to store per-conversation preferences. ### WebSocket Support (Optional) Real-time message delivery instead of 30-second polling: - Would require WebSocket infrastructure (e.g., FastAPI WebSocket, Redis pub/sub) - Significant infrastructure changes ## Migration The messaging tables are created by migration `e3f4a5b6c7d8_add_messaging_tables.py`: ```bash # Apply migration alembic upgrade head # Rollback alembic downgrade -1 ``` ## Navigation ### Admin Sidebar Messages is available under "Platform Administration" section. ### Store Sidebar Messages is available under "Sales" section. ### Shop Account Dashboard Messages card is available on the customer account dashboard with unread count badge. ### Header Badge Both admin and store headers show an unread message count badge next to the messages icon.