# 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

## Storefront (Customer) Interface

### API Endpoints (`/api/v1/storefront/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/storefront/account/messages.html`
- **Page Route:** `/storefront/account/messages` and `/storefront/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.

### Storefront 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.
