Move 39 documentation files from top-level docs/ into each module's docs/ folder, accessible via symlinks from docs/modules/. Create data-model.md files for 10 modules with full schema documentation. Replace originals with redirect stubs. Remove empty guide stubs. Modules migrated: tenancy, billing, loyalty, marketplace, orders, messaging, cms, catalog, inventory, hosting, prospecting. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
291 lines
13 KiB
Markdown
291 lines
13 KiB
Markdown
# Messaging Data Model
|
|
|
|
Entity relationships and database schema for the messaging module.
|
|
|
|
## Entity Relationship Overview
|
|
|
|
```
|
|
Store 1──1 StoreEmailSettings
|
|
Store 1──* StoreEmailTemplate
|
|
Store 1──* Conversation 1──* Message 1──* MessageAttachment
|
|
└──* ConversationParticipant
|
|
|
|
EmailTemplate 1──* EmailLog
|
|
```
|
|
|
|
## Models
|
|
|
|
### EmailTemplate
|
|
|
|
Multi-language email templates stored in database with Jinja2 variable interpolation.
|
|
|
|
| Field | Type | Constraints | Description |
|
|
|-------|------|-------------|-------------|
|
|
| `id` | Integer | PK | Primary key |
|
|
| `code` | String(100) | not null, indexed | Template identifier (e.g., "signup_welcome") |
|
|
| `language` | String(5) | not null, default "en" | Language code |
|
|
| `name` | String(255) | not null | Human-readable name |
|
|
| `description` | Text | nullable | Template purpose description |
|
|
| `category` | String(50) | not null, default "system", indexed | auth, orders, billing, system, marketing |
|
|
| `subject` | String(500) | not null | Subject line (supports variables) |
|
|
| `body_html` | Text | not null | HTML body content |
|
|
| `body_text` | Text | nullable | Plain text fallback |
|
|
| `variables` | Text | nullable | JSON list of expected variables |
|
|
| `required_variables` | Text | nullable | JSON list of mandatory variables |
|
|
| `is_active` | Boolean | not null, default True | Activation status |
|
|
| `is_platform_only` | Boolean | not null, default False | If True, stores cannot override |
|
|
| `created_at` | DateTime | tz-aware | Record creation time |
|
|
| `updated_at` | DateTime | tz-aware | Record update time |
|
|
|
|
**Unique Index**: `(code, language)`
|
|
|
|
### StoreEmailTemplate
|
|
|
|
Store-specific email template overrides. Stores can customize platform templates without modifying defaults.
|
|
|
|
| Field | Type | Constraints | Description |
|
|
|-------|------|-------------|-------------|
|
|
| `id` | Integer | PK | Primary key |
|
|
| `store_id` | Integer | FK, not null, indexed | Store owning the override |
|
|
| `template_code` | String(100) | not null, indexed | References EmailTemplate.code |
|
|
| `language` | String(5) | not null, default "en" | Language code |
|
|
| `name` | String(255) | nullable | Custom name (null = use platform) |
|
|
| `subject` | String(500) | not null | Custom subject line |
|
|
| `body_html` | Text | not null | Custom HTML body |
|
|
| `body_text` | Text | nullable | Custom plain text body |
|
|
| `is_active` | Boolean | not null, default True | Activation status |
|
|
| `created_at` | DateTime | tz-aware | Record creation time |
|
|
| `updated_at` | DateTime | tz-aware | Record update time |
|
|
|
|
**Unique Constraint**: `(store_id, template_code, language)`
|
|
|
|
### EmailLog
|
|
|
|
Email sending history and tracking for debugging, analytics, and compliance.
|
|
|
|
| Field | Type | Constraints | Description |
|
|
|-------|------|-------------|-------------|
|
|
| `id` | Integer | PK | Primary key |
|
|
| `template_code` | String(100) | nullable, indexed | Reference to template code |
|
|
| `template_id` | Integer | FK, nullable | Reference to template |
|
|
| `recipient_email` | String(255) | not null, indexed | Recipient address |
|
|
| `recipient_name` | String(255) | nullable | Recipient name |
|
|
| `subject` | String(500) | not null | Email subject line |
|
|
| `body_html` | Text | nullable | HTML body snapshot |
|
|
| `body_text` | Text | nullable | Plain text body snapshot |
|
|
| `from_email` | String(255) | not null | Sender email address |
|
|
| `from_name` | String(255) | nullable | Sender name |
|
|
| `reply_to` | String(255) | nullable | Reply-to address |
|
|
| `status` | String(20) | not null, default "pending", indexed | pending, sent, failed, bounced, delivered, opened, clicked |
|
|
| `sent_at` | DateTime | nullable | When sent |
|
|
| `delivered_at` | DateTime | nullable | When delivered |
|
|
| `opened_at` | DateTime | nullable | When opened |
|
|
| `clicked_at` | DateTime | nullable | When clicked |
|
|
| `error_message` | Text | nullable | Error details if failed |
|
|
| `retry_count` | Integer | not null, default 0 | Retry attempts |
|
|
| `provider` | String(50) | nullable | smtp, sendgrid, mailgun, ses |
|
|
| `provider_message_id` | String(255) | nullable, indexed | Provider's message ID |
|
|
| `store_id` | Integer | FK, nullable, indexed | Associated store |
|
|
| `user_id` | Integer | FK, nullable, indexed | Associated user |
|
|
| `related_type` | String(50) | nullable | Related entity type |
|
|
| `related_id` | Integer | nullable | Related entity ID |
|
|
| `extra_data` | Text | nullable | JSON additional context |
|
|
| `created_at` | DateTime | tz-aware | Record creation time |
|
|
| `updated_at` | DateTime | tz-aware | Record update time |
|
|
|
|
### StoreEmailSettings
|
|
|
|
Per-store email sending configuration. One-to-one with Store.
|
|
|
|
| Field | Type | Constraints | Description |
|
|
|-------|------|-------------|-------------|
|
|
| `id` | Integer | PK | Primary key |
|
|
| `store_id` | Integer | FK, unique, not null | One-to-one with store |
|
|
| `from_email` | String(255) | not null | Sender email address |
|
|
| `from_name` | String(100) | not null | Sender display name |
|
|
| `reply_to_email` | String(255) | nullable | Reply-to address |
|
|
| `signature_text` | Text | nullable | Plain text signature |
|
|
| `signature_html` | Text | nullable | HTML signature/footer |
|
|
| `provider` | String(20) | not null, default "smtp" | smtp, sendgrid, mailgun, ses |
|
|
| `smtp_host` | String(255) | nullable | SMTP server hostname |
|
|
| `smtp_port` | Integer | nullable, default 587 | SMTP port |
|
|
| `smtp_username` | String(255) | nullable | SMTP username |
|
|
| `smtp_password` | String(500) | nullable | SMTP password (encrypted) |
|
|
| `smtp_use_tls` | Boolean | not null, default True | Use TLS |
|
|
| `smtp_use_ssl` | Boolean | not null, default False | Use SSL (port 465) |
|
|
| `sendgrid_api_key` | String(500) | nullable | SendGrid API key (encrypted) |
|
|
| `mailgun_api_key` | String(500) | nullable | Mailgun API key (encrypted) |
|
|
| `mailgun_domain` | String(255) | nullable | Mailgun domain |
|
|
| `ses_access_key_id` | String(100) | nullable | SES access key ID |
|
|
| `ses_secret_access_key` | String(500) | nullable | SES secret key (encrypted) |
|
|
| `ses_region` | String(50) | nullable, default "eu-west-1" | AWS region |
|
|
| `is_configured` | Boolean | not null, default False | Has complete config |
|
|
| `is_verified` | Boolean | not null, default False | Test email succeeded |
|
|
| `last_verified_at` | DateTime | nullable, tz-aware | Last verification |
|
|
| `verification_error` | Text | nullable | Last error message |
|
|
| `created_at` | DateTime | tz-aware | Record creation time |
|
|
| `updated_at` | DateTime | tz-aware | Record update time |
|
|
|
|
**Index**: `(store_id, is_configured)`
|
|
|
|
### AdminNotification
|
|
|
|
Admin-specific notifications for system alerts and warnings.
|
|
|
|
| Field | Type | Constraints | Description |
|
|
|-------|------|-------------|-------------|
|
|
| `id` | Integer | PK | Primary key |
|
|
| `type` | String(50) | not null, indexed | system_alert, store_issue, import_failure |
|
|
| `priority` | String(20) | not null, default "normal", indexed | low, normal, high, critical |
|
|
| `title` | String(200) | not null | Notification title |
|
|
| `message` | Text | not null | Notification message |
|
|
| `is_read` | Boolean | not null, default False, indexed | Read status |
|
|
| `read_at` | DateTime | nullable | When read |
|
|
| `read_by_user_id` | Integer | FK, nullable | User who read it |
|
|
| `action_required` | Boolean | not null, default False, indexed | Action needed |
|
|
| `action_url` | String(500) | nullable | Link to relevant admin page |
|
|
| `notification_metadata` | JSON | nullable | Additional context |
|
|
| `created_at` | DateTime | tz-aware | Record creation time |
|
|
| `updated_at` | DateTime | tz-aware | Record update time |
|
|
|
|
### Conversation
|
|
|
|
Threaded conversation between participants with multi-tenant isolation.
|
|
|
|
| Field | Type | Constraints | Description |
|
|
|-------|------|-------------|-------------|
|
|
| `id` | Integer | PK | Primary key |
|
|
| `conversation_type` | Enum | not null, indexed | admin_store, store_customer, admin_customer |
|
|
| `subject` | String(500) | not null | Thread subject line |
|
|
| `store_id` | Integer | FK, nullable, indexed | Multi-tenant isolation |
|
|
| `is_closed` | Boolean | not null, default False | Closed status |
|
|
| `closed_at` | DateTime | nullable | When closed |
|
|
| `closed_by_type` | Enum | nullable | Type of closer |
|
|
| `closed_by_id` | Integer | nullable | ID of closer |
|
|
| `last_message_at` | DateTime | nullable, indexed | Last activity |
|
|
| `message_count` | Integer | not null, default 0 | Total messages |
|
|
| `created_at` | DateTime | tz-aware | Record creation time |
|
|
| `updated_at` | DateTime | tz-aware | Record update time |
|
|
|
|
**Composite Index**: `(conversation_type, store_id)`
|
|
|
|
### ConversationParticipant
|
|
|
|
Links participants (users or customers) to conversations with polymorphic relationships.
|
|
|
|
| Field | Type | Constraints | Description |
|
|
|-------|------|-------------|-------------|
|
|
| `id` | Integer | PK | Primary key |
|
|
| `conversation_id` | Integer | FK, not null, indexed | Parent conversation |
|
|
| `participant_type` | Enum | not null | admin, store, customer |
|
|
| `participant_id` | Integer | not null, indexed | Polymorphic participant ID |
|
|
| `store_id` | Integer | FK, nullable | Store context |
|
|
| `unread_count` | Integer | not null, default 0 | Unread messages |
|
|
| `last_read_at` | DateTime | nullable | Last read time |
|
|
| `email_notifications` | Boolean | not null, default True | Email notification pref |
|
|
| `muted` | Boolean | not null, default False | Muted status |
|
|
| `created_at` | DateTime | tz-aware | Record creation time |
|
|
| `updated_at` | DateTime | tz-aware | Record update time |
|
|
|
|
**Unique Constraint**: `(conversation_id, participant_type, participant_id)`
|
|
**Composite Index**: `(participant_type, participant_id)`
|
|
|
|
### Message
|
|
|
|
Individual message within a conversation thread.
|
|
|
|
| Field | Type | Constraints | Description |
|
|
|-------|------|-------------|-------------|
|
|
| `id` | Integer | PK | Primary key |
|
|
| `conversation_id` | Integer | FK, not null, indexed | Parent conversation |
|
|
| `sender_type` | Enum | not null | admin, store, customer |
|
|
| `sender_id` | Integer | not null, indexed | Polymorphic sender ID |
|
|
| `content` | Text | not null | Message body |
|
|
| `is_system_message` | Boolean | not null, default False | System-generated flag |
|
|
| `is_deleted` | Boolean | not null, default False | Soft delete flag |
|
|
| `deleted_at` | DateTime | nullable | When deleted |
|
|
| `deleted_by_type` | Enum | nullable | Type of deleter |
|
|
| `deleted_by_id` | Integer | nullable | ID of deleter |
|
|
| `created_at` | DateTime | tz-aware | Record creation time |
|
|
| `updated_at` | DateTime | tz-aware | Record update time |
|
|
|
|
**Composite Index**: `(conversation_id, created_at)`
|
|
|
|
### MessageAttachment
|
|
|
|
File attachments for messages.
|
|
|
|
| Field | Type | Constraints | Description |
|
|
|-------|------|-------------|-------------|
|
|
| `id` | Integer | PK | Primary key |
|
|
| `message_id` | Integer | FK, not null, indexed | Parent message |
|
|
| `filename` | String(255) | not null | System filename |
|
|
| `original_filename` | String(255) | not null | Original upload name |
|
|
| `file_path` | String(1000) | not null | Storage path |
|
|
| `file_size` | Integer | not null | File size in bytes |
|
|
| `mime_type` | String(100) | not null | MIME type |
|
|
| `is_image` | Boolean | not null, default False | Image flag |
|
|
| `image_width` | Integer | nullable | Width in pixels |
|
|
| `image_height` | Integer | nullable | Height in pixels |
|
|
| `thumbnail_path` | String(1000) | nullable | Thumbnail path |
|
|
| `created_at` | DateTime | tz-aware | Record creation time |
|
|
| `updated_at` | DateTime | tz-aware | Record update time |
|
|
|
|
## Enums
|
|
|
|
### EmailCategory
|
|
|
|
| Value | Description |
|
|
|-------|-------------|
|
|
| `auth` | Signup, password reset, verification |
|
|
| `orders` | Order confirmations, shipping |
|
|
| `billing` | Invoices, payment failures |
|
|
| `system` | Team invites, notifications |
|
|
| `marketing` | Newsletters, promotions |
|
|
|
|
### EmailStatus
|
|
|
|
| Value | Description |
|
|
|-------|-------------|
|
|
| `pending` | Queued for sending |
|
|
| `sent` | Sent to provider |
|
|
| `failed` | Send failed |
|
|
| `bounced` | Bounced back |
|
|
| `delivered` | Confirmed delivered |
|
|
| `opened` | Recipient opened |
|
|
| `clicked` | Link clicked |
|
|
|
|
### EmailProvider
|
|
|
|
| Value | Description |
|
|
|-------|-------------|
|
|
| `smtp` | Standard SMTP (all tiers) |
|
|
| `sendgrid` | SendGrid API (Business+ tier) |
|
|
| `mailgun` | Mailgun API (Business+ tier) |
|
|
| `ses` | Amazon SES (Business+ tier) |
|
|
|
|
### ConversationType
|
|
|
|
| Value | Description |
|
|
|-------|-------------|
|
|
| `admin_store` | Admin-store conversations |
|
|
| `store_customer` | Store-customer conversations |
|
|
| `admin_customer` | Admin-customer conversations |
|
|
|
|
### ParticipantType
|
|
|
|
| Value | Description |
|
|
|-------|-------------|
|
|
| `admin` | Platform admin user |
|
|
| `store` | Store team user |
|
|
| `customer` | Customer |
|
|
|
|
## Design Patterns
|
|
|
|
- **Template override system**: Platform templates + per-store overrides with language fallback
|
|
- **Polymorphic participants**: Conversations support admin, store, and customer participants
|
|
- **Email tracking**: Full lifecycle tracking (sent → delivered → opened → clicked)
|
|
- **Provider abstraction**: Multiple email providers with per-store configuration
|
|
- **Premium tier gating**: SendGrid, Mailgun, SES require Business+ tier
|
|
- **Soft deletes**: Messages support soft delete with audit trail
|