# Comment le système détecte le tenant via le numéro Twilio

## 🎯 Question : Comment détecte-t-on le tenant dans le callback SMS ?

**Réponse courte** : Via le numéro Twilio (paramètre `From`) qui est mappé au tenant dans la table `TwilioPhoneNumber`.

## 📊 Flux détaillé avec exemple concret

### Scénario : La Clinique ACME reçoit une confirmation SMS

#### 1️⃣ Configuration initiale (une fois)

**Table `twilio_phone_numbers` (schéma admin `saas_db`)** :
```
phone_number    | tenant_id  | friendly_name
+1234567890     | acme_corp  | Clinique ACME
```

**Table `tenants` (schéma admin `saas_db`)** :
```
tenant_id   | schema_name        | tenant_name
acme_corp   | tenant_acme_corp   | Clinique ACME
```

#### 2️⃣ Patient appelle la clinique

1. Patient compose : **+1234567890** (numéro Twilio de la Clinique ACME)
2. Twilio webhook `/api/voip/incoming-call` reçoit `To=+1234567890`
3. Système lookup : +1234567890 → tenant_id: `acme_corp` → schema: `tenant_acme_corp`
4. Données sauvegardées dans `tenant_acme_corp.inbound_call_data`

#### 3️⃣ Patient confirme le RDV via voicebot

1. OpenAI détecte `appointmentConfirmed = true`
2. Système envoie SMS de confirmation via TwilioSmsService
3. **Twilio envoie le SMS depuis +1234567890** (le numéro de la clinique)
4. SMS enregistré avec `smsSid = "SM123abc..."` et `smsStatus = "queued"`

#### 4️⃣ Callback Twilio arrive (statut SMS)

**Paramètres reçus** :
```http
POST /api/voip/sms/status-callback
From=+1234567890          ← Numéro Twilio (celui de la clinique)
To=+33612345678           ← Numéro du patient
MessageSid=SM123abc...
MessageStatus=delivered
```

#### 5️⃣ Identification du tenant (TwilioSmsCallbackController)

```java
// ÉTAPE 1 : Extraire le numéro Twilio
String from = "+1234567890";  // De Twilio callback

// ÉTAPE 2 : Chercher dans la table admin
TenantContext.setTenantId("admin");
Optional<TwilioPhoneNumber> phone = twilioPhoneNumberRepository
    .findByPhoneNumber(from);

// Résultat :
// phone.getTenantId() → "acme_corp"

// ÉTAPE 3 : Récupérer le schéma du tenant
Optional<Tenant> tenant = tenantRepository
    .findByTenantId("acme_corp");

// Résultat :
// tenant.getSchemaName() → "tenant_acme_corp"

// ÉTAPE 4 : Switch vers le bon schéma
TenantContext.setTenantId("tenant_acme_corp");

// ÉTAPE 5 : Mettre à jour le statut SMS dans la bonne base
inboundCallService.updateSmsStatus("SM123abc...", "delivered");

// ÉTAPE 6 : Cleanup
TenantContext.clear();
```

## 🔑 Points clés

### 1. Le numéro Twilio identifie le tenant

- Chaque tenant a son propre numéro Twilio
- Le numéro est enregistré dans `TwilioPhoneNumber` avec le `tenantId`
- C'est ce mapping qui permet l'identification automatique

### 2. Pourquoi `From` et pas `To` ?

Dans le callback SMS :
- **`From`** = Votre numéro Twilio (l'expéditeur du SMS) ✅ **On utilise celui-ci**
- **`To`** = Le numéro du patient (le destinataire) ❌ **Pas utile pour identifier le tenant**

### 3. Architecture multi-tenant invisible

```
Callback unique : /api/voip/sms/status-callback
                          ↓
         From = +1234567890 ou +1987654321 ?
                          ↓
                    TwilioPhoneNumber
                   /                  \
        +1234567890                +1987654321
              ↓                          ↓
         acme_corp                  medico_inc
              ↓                          ↓
      tenant_acme_corp          tenant_medico_inc
```

## 📝 Code source

### TwilioSmsCallbackController.java (lignes 57-102)

```java
try {
    // STEP 1: Identifier le tenant via le numéro Twilio (From)
    TenantContext.setTenantId("admin");
    
    Optional<TwilioPhoneNumber> twilioPhoneOpt = 
        twilioPhoneNumberRepository.findByPhoneNumber(from);
    
    if (twilioPhoneOpt.isEmpty()) {
        log.warn("⚠️ Numéro Twilio inconnu: {}", from);
        return "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response></Response>";
    }
    
    TwilioPhoneNumber twilioPhone = twilioPhoneOpt.get();
    String tenantId = twilioPhone.getTenantId();
    
    // STEP 2: Get tenant schema name
    Optional<Tenant> tenantOpt = tenantRepository.findByTenantId(tenantId);
    String schemaName = tenantOpt.get().getSchemaName();
    
    log.info("🏢 Tenant identifié via numéro Twilio {} → Tenant ID: {} | Schema: {}", 
            from, tenantId, schemaName);
    
    // STEP 3: Switch vers le schéma du tenant
    TenantContext.setTenantId(schemaName);
    
    // STEP 4: Mettre à jour le statut SMS
    boolean updated = inboundCallService.updateSmsStatus(messageSid, messageStatus);
    
} finally {
    TenantContext.clear();
}
```

## 🎨 Exemple avec 3 tenants

### Configuration
```sql
-- Table twilio_phone_numbers (saas_db)
+1234567890 → acme_corp   → tenant_acme_corp
+1987654321 → medico_inc  → tenant_medico_inc
+1555123456 → sante_plus  → tenant_sante_plus
```

### Callbacks reçus

**Callback 1** :
```
From: +1234567890
→ Détecte acme_corp
→ Update dans tenant_acme_corp ✅
```

**Callback 2** :
```
From: +1987654321
→ Détecte medico_inc
→ Update dans tenant_medico_inc ✅
```

**Callback 3** :
```
From: +1555123456
→ Détecte sante_plus
→ Update dans tenant_sante_plus ✅
```

### Résultat
✅ Une seule URL de callback
✅ Identification automatique
✅ Isolation parfaite des données

## 🚀 Avantages de cette approche

1. **Aucune configuration par tenant** - URL unique pour tous
2. **Sécurisé** - Le tenant est déterminé côté serveur (pas par l'URL)
3. **Scalable** - Ajoutez des tenants sans changer le code
4. **Maintenable** - Pas de URLs différentes à gérer
5. **Compatible** - Même pattern que les appels entrants

## ❓ FAQ

### Q: Que se passe-t-il si le numéro Twilio n'est pas trouvé ?

```java
if (twilioPhoneOpt.isEmpty()) {
    log.warn("⚠️ Numéro Twilio inconnu: {}", from);
    return "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response></Response>";
}
```
→ Le callback retourne une réponse vide, rien n'est mis à jour

### Q: Peut-on avoir plusieurs numéros Twilio pour un même tenant ?

Oui ! La table `TwilioPhoneNumber` permet cela :
```sql
+1234567890 → acme_corp
+1555999888 → acme_corp  (numéro secondaire)
```

### Q: Comment ajouter un nouveau tenant ?

1. Créer le tenant via l'API admin
2. Acheter un numéro Twilio
3. L'associer au tenant dans `TwilioPhoneNumber`
4. C'est tout ! Le callback fonctionne automatiquement
