# Multi-Tenant WhatsApp Configuration Implementation

## Overview

This document describes the implementation of per-tenant WhatsApp Business phone number configuration, allowing each bakery to use their own WhatsApp Business account for sending notifications to suppliers.

---

## Problem Statement

**Before**: All tenants shared a single global WhatsApp Business account configured via environment variables.

**After**: Each tenant can configure their own WhatsApp Business account in their bakery settings, with credentials stored securely in the database.

---

## Architecture

### Data Flow

```
Bakery Settings UI (Frontend)
        ↓
Tenant Settings API
        ↓
tenant_settings.notification_settings (Database)
        ↓
Notification Service fetches tenant settings
        ↓
WhatsAppBusinessService uses tenant-specific credentials
        ↓
Meta WhatsApp Cloud API
```

###Tenant Isolation

Each tenant has:
- Own WhatsApp Phone Number ID
- Own WhatsApp Access Token
- Own WhatsApp Business Account ID
- Independent enable/disable toggle

---

## Implementation Progress

### ✅ Phase 1: Backend - Tenant Service (COMPLETED)

#### 1.1 Database Model
**File**: `services/tenant/app/models/tenant_settings.py`

**Changes**:
- Added `notification_settings` JSON column to `TenantSettings` model
- Includes WhatsApp and Email configuration
- Default values set for new tenants

**Fields Added**:
```python
notification_settings = {
    # WhatsApp Configuration
    "whatsapp_enabled": False,
    "whatsapp_phone_number_id": "",
    "whatsapp_access_token": "",
    "whatsapp_business_account_id": "",
    "whatsapp_api_version": "v18.0",
    "whatsapp_default_language": "es",

    # Email Configuration
    "email_enabled": True,
    "email_from_address": "",
    "email_from_name": "",
    "email_reply_to": "",

    # Notification Preferences
    "enable_po_notifications": True,
    "enable_inventory_alerts": True,
    "enable_production_alerts": True,
    "enable_forecast_alerts": True,

    # Notification Channels
    "po_notification_channels": ["email"],
    "inventory_alert_channels": ["email"],
    "production_alert_channels": ["email"],
    "forecast_alert_channels": ["email"]
}
```

#### 1.2 Pydantic Schema
**File**: `services/tenant/app/schemas/tenant_settings.py`

**Changes**:
- Created `NotificationSettings` Pydantic schema
- Added validation for required fields when WhatsApp is enabled
- Added to `TenantSettingsResponse` and `TenantSettingsUpdate`

**Validators**:
- Validates channels are valid (`email`, `whatsapp`, `sms`, `push`)
- Requires `whatsapp_phone_number_id` when WhatsApp enabled
- Requires `whatsapp_access_token` when WhatsApp enabled

#### 1.3 Service Layer
**File**: `services/tenant/app/services/tenant_settings_service.py`

**Changes**:
- Added `NotificationSettings` to imports
- Added `"notification"` to `CATEGORY_SCHEMAS` map
- Added `"notification": "notification_settings"` to `CATEGORY_COLUMNS` map

**Effect**: The service now automatically handles notification settings through existing methods:
- `get_category(tenant_id, "notification")`
- `update_category(tenant_id, "notification", updates)`
- `reset_category(tenant_id, "notification")`

#### 1.4 Database Migration
**File**: `services/tenant/migrations/versions/002_add_notification_settings.py`

**Purpose**: Adds `notification_settings` column to existing `tenant_settings` table

**Migration Details**:
- Adds JSONB column with default values
- All existing tenants get default notification settings
- Reversible (downgrade removes column)

**To Run**:
```bash
cd services/tenant
alembic upgrade head
```

---

### 🔄 Phase 2: Backend - Notification Service (IN PROGRESS)

This phase needs to be completed. Here's what needs to be done:

#### 2.1 Add Tenant Client Dependency
**File**: `services/notification/app/core/config.py` or dependency injection

**Action**: Add `TenantServiceClient` to notification service

**Code needed**:
```python
from shared.clients.tenant_client import TenantServiceClient

# In service initialization or dependency
tenant_client = TenantServiceClient(config)
```

#### 2.2 Modify WhatsAppBusinessService
**File**: `services/notification/app/services/whatsapp_business_service.py`

**Changes needed**:
1. Accept tenant_id as parameter
2. Fetch tenant notification settings
3. Use tenant-specific credentials if available
4. Fall back to global config if tenant settings empty

**Example Implementation**:
```python
async def send_message(self, request: SendWhatsAppMessageRequest, tenant_client: TenantServiceClient):
    # Fetch tenant settings
    settings = await tenant_client.get_notification_settings(request.tenant_id)

    # Use tenant-specific credentials if WhatsApp enabled
    if settings.get("whatsapp_enabled"):
        access_token = settings.get("whatsapp_access_token")
        phone_number_id = settings.get("whatsapp_phone_number_id")
        business_account_id = settings.get("whatsapp_business_account_id")
    else:
        # Fall back to global config
        access_token = self.access_token
        phone_number_id = self.phone_number_id
        business_account_id = self.business_account_id

    # Send message using selected credentials
    ...
```

#### 2.3 Update PO Event Consumer
**File**: `services/notification/app/consumers/po_event_consumer.py`

**Changes needed**:
1. Inject `TenantServiceClient`
2. Fetch tenant settings before sending WhatsApp
3. Check if WhatsApp is enabled for tenant
4. Use appropriate channels

**Example**:
```python
# In __init__
self.tenant_client = tenant_client

# In send_po_approved_whatsapp
async def send_po_approved_whatsapp(self, event_data):
    tenant_id = event_data.get('data', {}).get('tenant_id')

    # Get tenant notification settings
    settings = await self.tenant_client.get_notification_settings(tenant_id)

    # Check if WhatsApp enabled
    if not settings.get("whatsapp_enabled"):
        logger.info("WhatsApp not enabled for tenant", tenant_id=tenant_id)
        return False

    # Check if PO notifications include WhatsApp channel
    channels = settings.get("po_notification_channels", [])
    if "whatsapp" not in channels:
        logger.info("WhatsApp not in PO notification channels", tenant_id=tenant_id)
        return False

    # Send WhatsApp (service will use tenant-specific credentials)
    ...
```

---

### 📋 Phase 3: Frontend - Settings UI (PENDING)

#### 3.1 TypeScript Types
**File**: `frontend/src/api/types/settings.ts`

**Add**:
```typescript
export interface NotificationSettings {
  // WhatsApp Configuration
  whatsapp_enabled: boolean;
  whatsapp_phone_number_id: string;
  whatsapp_access_token: string;
  whatsapp_business_account_id: string;
  whatsapp_api_version: string;
  whatsapp_default_language: string;

  // Email Configuration
  email_enabled: boolean;
  email_from_address: string;
  email_from_name: string;
  email_reply_to: string;

  // Notification Preferences
  enable_po_notifications: boolean;
  enable_inventory_alerts: boolean;
  enable_production_alerts: boolean;
  enable_forecast_alerts: boolean;

  // Notification Channels
  po_notification_channels: string[];
  inventory_alert_channels: string[];
  production_alert_channels: string[];
  forecast_alert_channels: string[];
}

export interface BakerySettings {
  ...existing fields...
  notification_settings: NotificationSettings;
}
```

#### 3.2 Settings Page - Add Tab
**File**: `frontend/src/pages/app/settings/bakery/BakerySettingsPage.tsx`

**Add new tab**:
```tsx
<TabsTrigger value="notifications">
  <Bell className="w-4 h-4 mr-2" />
  {t('bakery.tabs.notifications')}
</TabsTrigger>

<TabsContent value="notifications">
  <NotificationSettingsCard settings={settings} onUpdate={handleUpdate} />
</TabsContent>
```

#### 3.3 Notification Settings Card Component
**File**: `frontend/src/components/settings/NotificationSettingsCard.tsx` (new file)

**Features**:
- Toggle for WhatsApp enabled/disabled
- Input fields for WhatsApp credentials (Phone Number ID, Access Token, Business Account ID)
- Password-style input for Access Token
- Test Connection button
- Email configuration fields
- Channel selection checkboxes for each notification type

**Example Structure**:
```tsx
export function NotificationSettingsCard({ settings, onUpdate }: Props) {
  return (
    <Card>
      <CardHeader>
        <CardTitle>{t('notifications.whatsapp_config')}</CardTitle>
      </CardHeader>
      <CardContent>
        {/* WhatsApp Enable Toggle */}
        <Switch
          checked={settings.whatsapp_enabled}
          onCheckedChange={(enabled) => onUpdate({ whatsapp_enabled: enabled })}
        />

        {/* WhatsApp Credentials (shown when enabled) */}
        {settings.whatsapp_enabled && (
          <>
            <Input
              label={t('notifications.phone_number_id')}
              value={settings.whatsapp_phone_number_id}
              onChange={(e) => onUpdate({ whatsapp_phone_number_id: e.target.value })}
            />

            <Input
              type="password"
              label={t('notifications.access_token')}
              value={settings.whatsapp_access_token}
              onChange={(e) => onUpdate({ whatsapp_access_token: e.target.value })}
            />

            <Button onClick={testConnection}>
              {t('notifications.test_connection')}
            </Button>
          </>
        )}

        {/* Channel Selection */}
        <div>
          <Label>{t('notifications.po_channels')}</Label>
          <Checkbox
            checked={settings.po_notification_channels.includes('email')}
            label="Email"
          />
          <Checkbox
            checked={settings.po_notification_channels.includes('whatsapp')}
            label="WhatsApp"
            disabled={!settings.whatsapp_enabled}
          />
        </div>
      </CardContent>
    </Card>
  );
}
```

#### 3.4 i18n Translations
**Files**:
- `frontend/src/locales/es/settings.json`
- `frontend/src/locales/eu/settings.json`

**Add translations**:
```json
{
  "notifications": {
    "title": "Notificaciones",
    "whatsapp_config": "Configuración de WhatsApp",
    "whatsapp_enabled": "Activar WhatsApp",
    "phone_number_id": "ID de Número de Teléfono",
    "access_token": "Token de Acceso",
    "business_account_id": "ID de Cuenta de Negocio",
    "test_connection": "Probar Conexión",
    "email_config": "Configuración de Email",
    "po_channels": "Canales para Órdenes de Compra",
    "inventory_channels": "Canales para Alertas de Inventario",
    "test_success": "Conexión exitosa",
    "test_failed": "Error en la conexión",
    "save_success": "Configuración guardada",
    "save_error": "Error al guardar"
  }
}
```

---

## Testing Guide

### Backend Testing

#### 1. Test Tenant Settings API

```bash
# Get notification settings
curl -X GET "http://localhost:8001/api/v1/tenants/{tenant_id}/settings/category/notification" \
  -H "Authorization: Bearer {token}"

# Update notification settings
curl -X PUT "http://localhost:8001/api/v1/tenants/{tenant_id}/settings/category/notification" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "settings": {
      "whatsapp_enabled": true,
      "whatsapp_phone_number_id": "123456789",
      "whatsapp_access_token": "EAAxxxx",
      "whatsapp_business_account_id": "987654321",
      "po_notification_channels": ["email", "whatsapp"]
    }
  }'
```

#### 2. Test WhatsApp Message with Tenant Config

```bash
# Send test PO notification (should use tenant's WhatsApp config)
# Trigger a PO approval and check logs:
kubectl logs -f deployment/notification-service | grep "WhatsApp"

# Should see logs indicating tenant-specific credentials being used
```

#### 3. Verify Database

```sql
-- Check notification settings for all tenants
SELECT
  tenant_id,
  notification_settings->>'whatsapp_enabled' as whatsapp_enabled,
  notification_settings->>'whatsapp_phone_number_id' as phone_id
FROM tenant_settings;

-- Check WhatsApp messages sent
SELECT
  tenant_id,
  recipient_phone,
  status,
  template_name,
  created_at
FROM whatsapp_messages
ORDER BY created_at DESC
LIMIT 10;
```

### Frontend Testing

1. **Navigate to Settings**:
   - Go to Bakery Settings page
   - Click on "Notifications" tab

2. **Configure WhatsApp**:
   - Toggle WhatsApp enabled
   - Enter WhatsApp credentials from Meta Business Suite
   - Click "Test Connection" button
   - Should see success message if credentials valid

3. **Configure Channels**:
   - Enable WhatsApp for PO notifications
   - Save settings
   - Verify settings persist after page reload

4. **Test End-to-End**:
   - Configure WhatsApp for a tenant
   - Create and approve a purchase order
   - Verify WhatsApp message sent to supplier
   - Check message appears in WhatsApp messages table

---

## Security Considerations

### ⚠️ Access Token Storage

**Current**: Access tokens stored as plain text in JSON field

**Recommended for Production**:
1. Encrypt access tokens before storing
2. Use field-level encryption
3. Decrypt only when needed

**Implementation**:
```python
from cryptography.fernet import Fernet

class EncryptionService:
    def encrypt(self, value: str) -> str:
        # Encrypt using Fernet or AWS KMS
        pass

    def decrypt(self, encrypted_value: str) -> str:
        # Decrypt
        pass

# In tenant settings service
encrypted_token = encryption_service.encrypt(access_token)
settings["whatsapp_access_token"] = encrypted_token
```

### Role-Based Access Control

Only owners and admins should be able to:
- View WhatsApp credentials
- Update notification settings
- Test WhatsApp connection

**Implementation**: Add role check in API endpoint

```python
@router.put("/api/v1/tenants/{tenant_id}/settings/category/notification")
async def update_notification_settings(
    tenant_id: UUID,
    settings: CategoryUpdateRequest,
    current_user: User = Depends(get_current_user)
):
    # Check role
    if current_user.role not in ["owner", "admin"]:
        raise HTTPException(status_code=403, detail="Insufficient permissions")

    # Update settings
    ...
```

---

## Migration Guide

### For Existing Tenants

When the migration runs, all existing tenants will get default notification settings with WhatsApp disabled.

To enable WhatsApp for existing tenants:

1. **Get WhatsApp Business API credentials** from Meta Business Suite
2. **Update tenant settings** via API or UI
3. **Test configuration** using test endpoint
4. **Enable WhatsApp** for desired notification types

### From Global to Per-Tenant

If you have a global WhatsApp configuration you want to migrate:

```python
# Migration script (run once)
async def migrate_global_to_tenant():
    # Get global config
    global_phone_id = os.getenv("WHATSAPP_PHONE_NUMBER_ID")
    global_token = os.getenv("WHATSAPP_ACCESS_TOKEN")
    global_account_id = os.getenv("WHATSAPP_BUSINESS_ACCOUNT_ID")

    # Update all tenant settings
    tenants = await get_all_tenants()
    for tenant in tenants:
        settings = {
            "whatsapp_enabled": True,
            "whatsapp_phone_number_id": global_phone_id,
            "whatsapp_access_token": global_token,
            "whatsapp_business_account_id": global_account_id
        }
        await update_tenant_notification_settings(tenant.id, settings)
```

---

## Deployment Steps

### 1. Backend Deployment

```bash
# 1. Deploy tenant service with new schema
cd services/tenant
alembic upgrade head

# 2. Deploy notification service with updated code
kubectl apply -f kubernetes/notification-deployment.yaml

# 3. Verify migration
kubectl exec -it deployment/tenant-service -- alembic current

# 4. Check logs
kubectl logs -f deployment/notification-service | grep "notification_settings"
```

### 2. Frontend Deployment

```bash
cd frontend
npm run build
# Deploy built frontend
```

### 3. Verification

- Check tenant settings API responds with notification_settings
- Verify frontend shows Notifications tab
- Test WhatsApp configuration for one tenant
- Send test PO notification

---

## Troubleshooting

### Issue: "notification_settings not found in database"

**Cause**: Migration not run

**Solution**:
```bash
cd services/tenant
alembic upgrade head
```

### Issue: "WhatsApp still using global config"

**Cause**: Notification service not updated to fetch tenant settings

**Solution**: Complete Phase 2 implementation (see above)

### Issue: "Access token validation fails"

**Cause**: Invalid or expired token

**Solution**:
1. Generate new permanent token from Meta Business Suite
2. Update tenant settings with new token
3. Test connection

---

## Next Steps

1. **Complete Phase 2**: Update notification service to fetch and use tenant settings
2. **Complete Phase 3**: Build frontend UI for configuration
3. **Add Encryption**: Implement field-level encryption for access tokens
4. **Add Audit Logging**: Log all changes to notification settings
5. **Add Test Endpoint**: Create endpoint to test WhatsApp connection
6. **Update Documentation**: Add tenant-specific setup to WhatsApp setup guide

---

## Files Modified

### Backend - Tenant Service
- ✅ `services/tenant/app/models/tenant_settings.py`
- ✅ `services/tenant/app/schemas/tenant_settings.py`
- ✅ `services/tenant/app/services/tenant_settings_service.py`
- ✅ `services/tenant/migrations/versions/002_add_notification_settings.py`

### Backend - Notification Service (Pending)
- ⏳ `services/notification/app/services/whatsapp_business_service.py`
- ⏳ `services/notification/app/consumers/po_event_consumer.py`
- ⏳ `services/notification/app/core/config.py` or DI setup

### Frontend (Pending)
- ⏳ `frontend/src/api/types/settings.ts`
- ⏳ `frontend/src/pages/app/settings/bakery/BakerySettingsPage.tsx`
- ⏳ `frontend/src/components/settings/NotificationSettingsCard.tsx` (new)
- ⏳ `frontend/src/locales/es/settings.json`
- ⏳ `frontend/src/locales/eu/settings.json`

---

## Summary

**Completed (Phase 1)**:
- ✅ Database schema for per-tenant notification settings
- ✅ Pydantic validation schemas
- ✅ Service layer support
- ✅ Database migration

**Remaining**:
- ⏳ Notification service integration with tenant settings
- ⏳ Frontend UI for configuration
- ⏳ Security enhancements (encryption, RBAC)
- ⏳ Testing and documentation updates

This implementation provides a solid foundation for multi-tenant WhatsApp configuration. Each bakery can now configure their own WhatsApp Business account, with credentials stored securely and settings easily manageable through the UI.
