## AI Copilot Module System
- Add copilot_enabled flag to businesses table
- Add Copilot Module toggle in Filament admin (Premium Features)
- Gate all Copilot buttons with copilot_enabled check
- Enable by default for Cannabrands only
## AI Settings Multi-Provider Support
- Support 5 AI providers: Anthropic, OpenAI, Perplexity, Canva, Jasper
- Separate encrypted API keys per provider
- Model dropdowns populated from config/ai.php
- Test Connection feature with real API validation
- Existing Connections summary shows status for all providers
- Provider-specific settings only shown when provider selected
## Brand-Scoped Campaign System
- Add brand_id to broadcasts table
- Brand selector component (reusable across forms)
- Campaign create/edit requires brand selection
- All campaigns now scoped to specific brand
## Documentation (9 New Files)
- docs/modules.md - Module system architecture
- docs/messaging.md - Messaging and conversation system
- docs/copilot.md - AI Copilot features and configuration
- docs/segmentation.md - Buyer segmentation system
- docs/sendportal.md - SendPortal multi-brand integration
- docs/campaigns.md - Campaign creation and delivery flow
- docs/conversations.md - Conversation lifecycle and threading
- docs/brand-settings.md - Brand configuration and voice system
- docs/architecture.md - High-level system overview
## Bug Fixes
- Remove duplicate FailedJobResource (Horizon already provides this at /horizon/failed)
- Fix missing Action import in Filament resources
- Update brand policy for proper access control
## Database Migrations
- 2025_11_23_175211_add_copilot_enabled_to_businesses_table.php
- 2025_11_23_180000_add_brand_id_to_broadcasts_table.php
- 2025_11_23_180326_update_ai_settings_for_multiple_providers.php
- 2025_11_23_184331_add_new_ai_providers_to_ai_settings.php
## Notes
- Pint: ✅ Passed (all code style checks)
- Tests: Failing due to pre-existing database schema dump conflicts (not related to these changes)
- Schema issue needs separate fix: pgsql-schema.sql contains tables that migrations also create
5.4 KiB
5.4 KiB
Messaging System Architecture
Overview
The messaging system provides unified conversation threading for Email and SMS communications between brands and their buyers. All messages are organized into conversations with full delivery tracking.
Database Schema
Tables
conversations
id- Primary keybrand_id- Owner brandbuyer_business_id- Buyer/contact businesscontact_id- Specific contact (nullable)subject- Conversation subjectstatus-open,closedlast_message_at- Timestamp of most recent messagecreated_at,updated_at
messages
id- Primary keyconversation_id- Parent conversationbrand_id- Sending/receiving branddirection-inboundoroutboundchannel-emailorsmsfrom- Sender address/numberto- Recipient address/number (can be JSON array for multi-recipient)subject- Email subject (nullable for SMS)body- Message content (HTML for email, plain text for SMS)message_id- External provider message IDin_reply_to- Email threading headerreferences- Email threading referencesdelivery_status- Delivery state (see below)delivery_status_detail- Provider-specific status detaildelivery_attempted_at- When delivery was attempteddelivery_detail_message- Human-readable delivery messagecreated_at,updated_at
conversation_participants
conversation_idparticipant_type-App\Models\BusinessorApp\Models\Contactparticipant_idjoined_atleft_at(nullable)
Inbound Message Flow
Inbound Email
- Receiving: Email arrives at brand's custom inbox (e.g.,
support@cannabrands.sendportal.io) - Mailbox Processing:
BrandEmailMailboxclass processes via Laravel Mailbox - Parsing:
- Extract
From,To,Subject,Body,Message-ID,In-Reply-To,References - Identify brand from recipient email
- Find or create contact from sender email
- Extract
- Threading:
- Check for existing conversation using
In-Reply-ToorReferencesheaders - If found, append to conversation
- If not found, create new conversation
- Check for existing conversation using
- Storage: Create
Messagerecord withdirection = 'inbound',channel = 'email'
Inbound SMS
- Receiving: SMS webhook from Twilio/provider hits
/webhooks/sms/inbound - Controller Processing:
SmsController@handleInbound - Parsing:
- Extract
From(phone number),To(brand's phone number),Body - Identify brand from recipient phone number
- Find or create contact from sender phone number
- Extract
- Threading:
- Check for existing open conversation between brand and contact
- If found and recent, append to conversation
- If not found or old, create new conversation
- Storage: Create
Messagerecord withdirection = 'inbound',channel = 'sms'
Outbound Message Flow
Outbound Email
- Composition: Brand composes message in
/s/{business}/messaging/{conversation}/show - Sending:
- Use brand's configured email channel (SendPortal, SMTP, etc.)
- Set
Fromto brand's email - Set
Message-ID,In-Reply-To,Referencesfor threading
- Storage: Create
Messagerecord withdirection = 'outbound',channel = 'email' - Delivery Tracking:
- Initial status:
pendingorqueued - Provider callbacks update status (see Delivery Status below)
- Initial status:
Outbound SMS
- Composition: Brand composes SMS message
- Sending:
- Use Twilio API with brand's phone number
- Character limit: 1600 chars (10 segments)
- Storage: Create
Messagerecord withdirection = 'outbound',channel = 'sms' - Delivery Tracking: Twilio webhooks update delivery status
Delivery Status Fields
delivery_status Enum
| Status | Description | Color |
|---|---|---|
pending |
Queued, not yet sent | Gray |
sent |
Successfully handed to provider | Blue |
delivered |
Confirmed delivered to recipient | Green |
failed |
Delivery failed | Red |
bounced |
Email bounced | Red |
opened |
Email opened (tracking pixel) | Green |
clicked |
Link clicked in message | Green |
delivery_status_detail
Provider-specific status code:
- Twilio:
delivered,undelivered,failed,queued,sent,receiving,received - SendPortal: Event types from webhook
- SMTP: Bounce codes, error messages
delivery_detail_message
Human-readable message:
- "Delivered to recipient's device"
- "Message bounced: Invalid email address"
- "Failed: Phone number unreachable"
delivery_attempted_at
Timestamp when delivery was last attempted (for retries and tracking).
Conversation Features
Filters
Available in /s/{business}/messaging/index:
- Status:
all,open,closed - Unread: Show conversations with unread messages
- Channel:
email,sms, orall
Search
Full-text search across:
- Conversation subject
- Participant names/emails
- Message body content
Close/Reopen
- Close: Mark conversation as
closed(still viewable, no notifications) - Reopen: Mark as
openagain (resumes notifications) - Route:
POST /s/{business}/messaging/{conversation}/closeor/reopen
Timeline Display Rules
Messages displayed in chronological order with:
- Sender name/email/phone
- Timestamp (relative: "2 hours ago")
- Direction indicator (inbound badge vs outbound styling)
- Delivery status badge (for outbound messages)
- Channel icon (email/SMS)