# Implementation Plan: Multi-Email Ticketing System

## Executive Summary

Add support for multiple email addresses per business in the ticketing system, with color-coded visual indicators and per-email IMAP/SMTP configuration.

## Current System Analysis

### Existing Components

1. **Django Backend (`tickets` app)**
   - `Ticket` model: Core ticket entity
   - `TicketComment` model: Ticket responses
   - `TicketEmailSettings` model: **Singleton** platform-wide email config
   - `IncomingTicketEmail` model: Email audit log
   - `TicketEmailReceiver` class: IMAP email fetching
   - `TicketEmailService` class: SMTP email sending

2. **Frontend**
   - `Tickets.tsx`: Main ticket listing page
   - `TicketModal.tsx`: Ticket detail modal
   - `useTickets` hook: Fetch tickets
   - `useTicketEmailSettings` hook: Manage email settings (singleton)
   - `Settings.tsx`: Business settings page

3. **Current Email Flow**
   - Single email account configured platform-wide
   - Emails matched to tickets by ID in subject/address
   - Comments created from email replies
   - New tickets created from unmatched emails

## Requirements (from user clarification)

1. **Per-Business Email Addresses**
   - Each business provides their own email account(s) and credentials
   - Multiple email addresses per business
   - Each email has independent IMAP/SMTP settings

2. **Email Address Properties**
   - Display name (e.g., "Support", "Billing")
   - Email address
   - IMAP settings (host, port, username, password, SSL)
   - SMTP settings (host, port, username, password, TLS/SSL)
   - Color for visual identification (hex color code)
   - Active/inactive status

3. **Ticket Routing**
   - Incoming emails matched to business by email address configuration
   - Reply emails matched to existing tickets
   - New emails create tickets for that business
   - System attempts to match sender email to customer/staff in business

4. **UI Requirements**
   - Colored left border on ticket rows indicating source email
   - Business settings page to manage email addresses
   - Test connection buttons for IMAP/SMTP
   - Email address selector when creating tickets manually

## Implementation Plan

### Phase 1: Django Backend Models

#### 1.1 Create `TicketEmailAddress` Model

**File:** `/home/poduck/Desktop/smoothschedule2/smoothschedule/tickets/models.py`

```python
class TicketEmailAddress(models.Model):
    """
    Per-business email address configuration for ticket management.
    Each business can have multiple email addresses with their own settings.
    """
    tenant = models.ForeignKey(
        Tenant,
        on_delete=models.CASCADE,
        related_name='ticket_email_addresses',
        help_text="Business this email address belongs to"
    )

    # Display information
    display_name = models.CharField(
        max_length=100,
        help_text="Display name (e.g., 'Support', 'Billing', 'Sales')"
    )
    email_address = models.EmailField(
        help_text="Email address for sending/receiving tickets"
    )
    color = models.CharField(
        max_length=7,
        default='#3b82f6',
        help_text="Hex color code for visual identification (e.g., #3b82f6)"
    )

    # IMAP settings (inbound)
    imap_host = models.CharField(max_length=255)
    imap_port = models.IntegerField(default=993)
    imap_use_ssl = models.BooleanField(default=True)
    imap_username = models.CharField(max_length=255)
    imap_password = models.CharField(max_length=255)  # Encrypted in production
    imap_folder = models.CharField(max_length=100, default='INBOX')

    # SMTP settings (outbound)
    smtp_host = models.CharField(max_length=255)
    smtp_port = models.IntegerField(default=587)
    smtp_use_tls = models.BooleanField(default=True)
    smtp_use_ssl = models.BooleanField(default=False)
    smtp_username = models.CharField(max_length=255)
    smtp_password = models.CharField(max_length=255)  # Encrypted in production

    # Status and tracking
    is_active = models.BooleanField(
        default=True,
        help_text="Whether this email address is actively checked"
    )
    is_default = models.BooleanField(
        default=False,
        help_text="Default email for new tickets in this business"
    )
    last_check_at = models.DateTimeField(null=True, blank=True)
    last_error = models.TextField(blank=True, default='')
    emails_processed_count = models.IntegerField(default=0)

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['-is_default', 'display_name']
        unique_together = [['tenant', 'email_address']]
        indexes = [
            models.Index(fields=['tenant', 'is_active']),
            models.Index(fields=['email_address']),
        ]

    def __str__(self):
        return f"{self.display_name} <{self.email_address}> ({self.tenant.name})"

    def save(self, *args, **kwargs):
        # Ensure only one default per tenant
        if self.is_default:
            TicketEmailAddress.objects.filter(
                tenant=self.tenant,
                is_default=True
            ).exclude(pk=self.pk).update(is_default=False)
        super().save(*args, **kwargs)
```

#### 1.2 Update `Ticket` Model

Add field to track which email address received/sent the ticket:

```python
class Ticket(models.Model):
    # ... existing fields ...

    source_email_address = models.ForeignKey(
        'TicketEmailAddress',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='tickets',
        help_text="Email address this ticket was received from or sent to"
    )
```

#### 1.3 Update `IncomingTicketEmail` Model

Add field to track which email address received the email:

```python
class IncomingTicketEmail(models.Model):
    # ... existing fields ...

    email_address = models.ForeignKey(
        'TicketEmailAddress',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='incoming_emails',
        help_text="Email address configuration that received this email"
    )
```

### Phase 2: Django Backend Logic

#### 2.1 Update Email Receiver

**File:** `/home/poduck/Desktop/smoothschedule2/smoothschedule/tickets/email_receiver.py`

- Modify `TicketEmailReceiver` to iterate through all active `TicketEmailAddress` objects
- Connect to each email address's IMAP server
- Process emails for each address
- Associate processed tickets with the source email address

#### 2.2 Update Email Sender

**File:** `/home/poduck/Desktop/smoothschedule2/smoothschedule/tickets/email_notifications.py`

- Modify `TicketEmailService` to use the ticket's `source_email_address` for sending
- Fall back to business's default email address if none specified

### Phase 3: Django Backend API

#### 3.1 Create Serializers

**File:** `/home/poduck/Desktop/smoothschedule2/smoothschedule/tickets/serializers.py`

```python
class TicketEmailAddressSerializer(serializers.ModelSerializer):
    class Meta:
        model = TicketEmailAddress
        fields = [
            'id', 'tenant', 'display_name', 'email_address', 'color',
            'imap_host', 'imap_port', 'imap_use_ssl', 'imap_username',
            'imap_password', 'imap_folder',
            'smtp_host', 'smtp_port', 'smtp_use_tls', 'smtp_use_ssl',
            'smtp_username', 'smtp_password',
            'is_active', 'is_default', 'last_check_at', 'last_error',
            'emails_processed_count', 'created_at', 'updated_at'
        ]
        read_only_fields = ['tenant', 'last_check_at', 'last_error',
                            'emails_processed_count', 'created_at', 'updated_at']
        extra_kwargs = {
            'imap_password': {'write_only': True},
            'smtp_password': {'write_only': True},
        }

class TicketEmailAddressListSerializer(serializers.ModelSerializer):
    """Lightweight serializer without passwords"""
    class Meta:
        model = TicketEmailAddress
        fields = [
            'id', 'display_name', 'email_address', 'color',
            'is_active', 'is_default', 'last_check_at',
            'emails_processed_count'
        ]
```

Update `TicketSerializer` to include email address:

```python
class TicketSerializer(serializers.ModelSerializer):
    # ... existing fields ...
    source_email_address = TicketEmailAddressListSerializer(read_only=True)
```

#### 3.2 Create ViewSet

**File:** `/home/poduck/Desktop/smoothschedule2/smoothschedule/tickets/views.py`

```python
class TicketEmailAddressViewSet(viewsets.ModelViewSet):
    """
    ViewSet for managing ticket email addresses.
    Only business owners and managers can manage email addresses.
    """
    serializer_class = TicketEmailAddressSerializer
    permission_classes = [IsTenantUser]

    def get_queryset(self):
        user = self.request.user
        # Business users see their own email addresses
        if user.role in ['owner', 'manager', 'staff']:
            return TicketEmailAddress.objects.filter(
                tenant=user.tenant
            )
        # Platform users see all
        elif user.role in ['superuser', 'platform_manager']:
            return TicketEmailAddress.objects.all()
        return TicketEmailAddress.objects.none()

    def get_serializer_class(self):
        if self.action == 'list':
            return TicketEmailAddressListSerializer
        return TicketEmailAddressSerializer

    def perform_create(self, serializer):
        # Automatically set tenant from current user
        serializer.save(tenant=self.request.user.tenant)

    @action(detail=True, methods=['post'])
    def test_imap(self, request, pk=None):
        """Test IMAP connection for this email address"""
        email_address = self.get_object()
        # Test IMAP connection logic
        return Response({'status': 'success'})

    @action(detail=True, methods=['post'])
    def test_smtp(self, request, pk=None):
        """Test SMTP connection for this email address"""
        email_address = self.get_object()
        # Test SMTP connection logic
        return Response({'status': 'success'})

    @action(detail=True, methods=['post'])
    def fetch_now(self, request, pk=None):
        """Manually trigger email fetch for this address"""
        email_address = self.get_object()
        # Trigger email fetch
        return Response({'status': 'fetching'})
```

#### 3.3 Add URL Routes

**File:** `/home/poduck/Desktop/smoothschedule2/smoothschedule/tickets/urls.py`

```python
router.register(r'email-addresses', views.TicketEmailAddressViewSet, basename='ticketemailaddress')
```

### Phase 4: Frontend - React Hooks

#### 4.1 Create API Client Functions

**File:** `/home/poduck/Desktop/smoothschedule2/frontend/src/api/ticketEmailAddresses.ts` (new file)

```typescript
export interface TicketEmailAddress {
  id: number;
  display_name: string;
  email_address: string;
  color: string;
  imap_host: string;
  imap_port: number;
  imap_use_ssl: boolean;
  imap_username: string;
  imap_password?: string;
  imap_folder: string;
  smtp_host: string;
  smtp_port: number;
  smtp_use_tls: boolean;
  smtp_use_ssl: boolean;
  smtp_username: string;
  smtp_password?: string;
  is_active: boolean;
  is_default: boolean;
  last_check_at?: string;
  last_error?: string;
  emails_processed_count: number;
  created_at: string;
  updated_at: string;
}

export type TicketEmailAddressCreate = Omit<TicketEmailAddress, 'id' | 'last_check_at' | 'last_error' | 'emails_processed_count' | 'created_at' | 'updated_at'>;

export const getTicketEmailAddresses = async (): Promise<TicketEmailAddress[]> => {
  const response = await apiClient.get('/tickets/email-addresses/');
  return response.data;
};

export const createTicketEmailAddress = async (data: TicketEmailAddressCreate): Promise<TicketEmailAddress> => {
  const response = await apiClient.post('/tickets/email-addresses/', data);
  return response.data;
};

export const updateTicketEmailAddress = async (id: number, data: Partial<TicketEmailAddressCreate>): Promise<TicketEmailAddress> => {
  const response = await apiClient.patch(`/tickets/email-addresses/${id}/`, data);
  return response.data;
};

export const deleteTicketEmailAddress = async (id: number): Promise<void> => {
  await apiClient.delete(`/tickets/email-addresses/${id}/`);
};

export const testImapConnection = async (id: number): Promise<{ status: string; message?: string }> => {
  const response = await apiClient.post(`/tickets/email-addresses/${id}/test_imap/`);
  return response.data;
};

export const testSmtpConnection = async (id: number): Promise<{ status: string; message?: string }> => {
  const response = await apiClient.post(`/tickets/email-addresses/${id}/test_smtp/`);
  return response.data;
};

export const fetchEmailsNow = async (id: number): Promise<{ status: string }> => {
  const response = await apiClient.post(`/tickets/email-addresses/${id}/fetch_now/`);
  return response.data;
};
```

#### 4.2 Create React Query Hooks

**File:** `/home/poduck/Desktop/smoothschedule2/frontend/src/hooks/useTicketEmailAddresses.ts` (new file)

```typescript
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import {
  getTicketEmailAddresses,
  createTicketEmailAddress,
  updateTicketEmailAddress,
  deleteTicketEmailAddress,
  testImapConnection,
  testSmtpConnection,
  fetchEmailsNow,
  TicketEmailAddress,
  TicketEmailAddressCreate,
} from '../api/ticketEmailAddresses';

const QUERY_KEY = 'ticketEmailAddresses';

export const useTicketEmailAddresses = () => {
  return useQuery<TicketEmailAddress[]>({
    queryKey: [QUERY_KEY],
    queryFn: getTicketEmailAddresses,
  });
};

export const useCreateTicketEmailAddress = () => {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: (data: TicketEmailAddressCreate) => createTicketEmailAddress(data),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: [QUERY_KEY] });
    },
  });
};

export const useUpdateTicketEmailAddress = () => {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: ({ id, data }: { id: number; data: Partial<TicketEmailAddressCreate> }) =>
      updateTicketEmailAddress(id, data),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: [QUERY_KEY] });
    },
  });
};

export const useDeleteTicketEmailAddress = () => {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: (id: number) => deleteTicketEmailAddress(id),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: [QUERY_KEY] });
    },
  });
};

export const useTestImapConnection = () => {
  return useMutation({
    mutationFn: (id: number) => testImapConnection(id),
  });
};

export const useTestSmtpConnection = () => {
  return useMutation({
    mutationFn: (id: number) => testSmtpConnection(id),
  });
};

export const useFetchEmailsNow = () => {
  return useMutation({
    mutationFn: (id: number) => fetchEmailsNow(id),
  });
};
```

### Phase 5: Frontend - React Components

#### 5.1 Email Address Management Component

**File:** `/home/poduck/Desktop/smoothschedule2/frontend/src/components/TicketEmailAddressManager.tsx` (new file)

Features:
- List all email addresses for the business
- Add new email address
- Edit existing email address
- Delete email address
- Test IMAP/SMTP connections
- Set default email address
- Color picker for visual identification
- Enable/disable email addresses

#### 5.2 Update Ticket List UI

**File:** `/home/poduck/Desktop/smoothschedule2/frontend/src/pages/Tickets.tsx`

Modify ticket rows to include colored left border:

```tsx
<div
  className="ticket-row"
  style={{
    borderLeft: ticket.source_email_address
      ? `4px solid ${ticket.source_email_address.color}`
      : '4px solid transparent'
  }}
>
  {/* Ticket content */}
</div>
```

#### 5.3 Update Types

**File:** `/home/poduck/Desktop/smoothschedule2/frontend/src/types.ts`

```typescript
export interface TicketEmailAddress {
  id: number;
  display_name: string;
  email_address: string;
  color: string;
  is_active: boolean;
  is_default: boolean;
  last_check_at?: string;
  emails_processed_count: number;
}

export interface Ticket {
  // ... existing fields ...
  source_email_address?: TicketEmailAddress;
}
```

#### 5.4 Add to Business Settings

**File:** `/home/poduck/Desktop/smoothschedule2/frontend/src/pages/Settings.tsx`

Add new tab for "Email Addresses" that renders `TicketEmailAddressManager` component.

### Phase 6: Database Migration

#### 6.1 Create Migration

```bash
cd /home/poduck/Desktop/smoothschedule2/smoothschedule
docker compose -f docker-compose.local.yml exec django python manage.py makemigrations tickets
```

#### 6.2 Run Migration

```bash
docker compose -f docker-compose.local.yml exec django python manage.py migrate tickets
```

#### 6.3 Data Migration (if needed)

If there's existing `TicketEmailSettings` data, create a data migration to convert it to `TicketEmailAddress` records for each tenant.

### Phase 7: Testing

#### 7.1 Backend Tests

- Test email address CRUD operations
- Test email receiver with multiple addresses
- Test email sender using correct source address
- Test tenant isolation

#### 7.2 Frontend Tests

- Test email address list rendering
- Test add/edit/delete operations
- Test connection testing UI
- Test ticket list color borders

### Phase 8: Documentation

#### 8.1 User Documentation

- How to add email addresses
- How to configure IMAP/SMTP settings
- How to test connections
- Color coding explanation

#### 8.2 Developer Documentation

- API endpoints documentation
- Model relationships
- Email processing flow
- Celery task schedule (if applicable)

## Migration Strategy

### Option 1: Keep Legacy System (Recommended)

- Keep `TicketEmailSettings` for platform-level configuration
- New `TicketEmailAddress` for per-business configuration
- Businesses can opt-in to multi-email system
- Existing single-email businesses continue working

### Option 2: Full Migration

- Deprecate `TicketEmailSettings`
- Migrate all existing data to `TicketEmailAddress`
- All businesses use new system

**Recommendation:** Option 1 for backward compatibility

## Risks & Considerations

1. **Security**
   - Email passwords stored in database (consider encryption)
   - SMTP/IMAP credentials exposure risk
   - Recommend OAuth2 for Gmail/Outlook in future

2. **Performance**
   - Multiple IMAP connections may increase load
   - Consider Celery task queue for email fetching
   - Implement rate limiting

3. **Email Deliverability**
   - Each business responsible for their own SPF/DKIM records
   - No centralized email reputation management

4. **UI/UX**
   - Color picker needs to be user-friendly
   - Color accessibility (contrast ratio)
   - Mobile responsiveness

## Future Enhancements

1. **OAuth2 Support**
   - Google Workspace integration
   - Microsoft 365 integration

2. **Email Templates Per Address**
   - Different signatures per email address
   - Custom auto-responses

3. **Analytics**
   - Email volume by address
   - Response time by address

4. **Auto-Assignment**
   - Route tickets to specific staff based on email address

## Implementation Timeline

- **Phase 1-2 (Backend Models & Logic):** 2-3 days
- **Phase 3 (Backend API):** 1-2 days
- **Phase 4-5 (Frontend):** 3-4 days
- **Phase 6-7 (Migration & Testing):** 1-2 days
- **Phase 8 (Documentation):** 1 day

**Total Estimated Time:** 8-12 days

## Approval Required

Before proceeding with implementation, please confirm:

1. ✅ Per-business email addresses (not platform-wide)
2. ✅ Businesses provide their own IMAP/SMTP credentials
3. ✅ Colored left border for visual identification
4. ✅ Email address management in business settings (not platform dashboard)
5. ⚠️ Security approach for storing email passwords
6. ⚠️ Migration strategy (keep legacy vs full migration)

## Questions for Product Owner

1. Should we encrypt email passwords in the database?
2. Do we need email address approval workflow (platform admin approval)?
3. Should there be a limit on number of email addresses per business?
4. Do we need email forwarding (forward to another address)?
5. Should unmatched emails (not tied to a ticket) create new tickets or be ignored?
