LA BIBLE DE LA PLATEFORME UNIFIÉE — ADDENDUM 06
Migration × Contacts × WebaBox — Gestionnaire Multi-Contacts
Version: 1.0
Date: 6 juin 2026
Auteur: Alain Bessette, CFO/Product Owner, ABI Conglomerate
Domaine: GoWeBa.com
Statut: Addendum Stratégique Officiel — Spécification Contraignante
Contraintes: ZÉRO perte de données · ZÉRO réinitialisation forcée · ZÉRO interruption d'envoi/réception de courriels
⚠️ AVIS CRITIQUE
Cet addendum possède la MÊME autorité que la Partie 1, la Partie 2 et tous les addendums précédents de la Bible.
Tous les changements décrits ici sont déployés en production et sauvegardés par points de contrôle.
Aucune modification incompatible avec le schéma n'a été effectuée. Toutes les modifications sont rétrocompatibles.
📋 TABLE DES MATIÈRES
- Phase A — Correction de catégorie WebaBox
- Phase B.1 — Bouton de suppression de migration
- Phase B.2 — Déconnexion du compte Google
- Phase B.3 — Enrichissement automatique lors de la migration
- Phase B.4 — Moteur de classification WebaCategory + Archivage 90 jours
- Phase C.1 — Onglet Chronologie du contact
- Phase C.2 — Onglet Pièces jointes (code couleur + aperçu + plein écran)
- Phase C.3 — Onglet Journal de fusion
- Phase C.4 — Onglet Analyse IA
- Phase D — Enrichissement par lot et vérification post-migration
- Phase E — Gestionnaire Multi-Contacts (Enrichissement relationnel + Sécurité de fusion)
- Corrections de bogues
- Fichiers modifiés — Inventaire complet
- Chronologie des points de contrôle
<a id="phase-a"></a>
SECTION 1 : PHASE A — CORRECTION DE CATÉGORIE WEBABOX
1.1 Énoncé du problème
L'API PATCH de WebaBox (/api/inbox/threads/[id]) définissait webaCategory: 'CONVERSATIONS' lorsqu'un utilisateur répondait à un fil URGENT. Or, CONVERSATIONS n'est pas une valeur valide dans l'énumération WebaCategory.
Valeurs valides de l'énumération : URGENT, IMPORTANT, JOURNAL, OFFICE, NONE.
1.2 Cause racine
Dans webabox-client.tsx, le gestionnaire de réponse codait en dur webaCategory: 'CONVERSATIONS' au lieu de la valeur correcte webaCategory: 'NONE'.
1.3 Correction appliquée
Fichier : app/(app)/webabox/webabox-client.tsx
Modification : webaCategory: 'CONVERSATIONS' → webaCategory: 'NONE'
1.4 Comportement après correction
| Action | Avant | Après |
|---|---|---|
| Répondre à un fil URGENT | Le fil passe dans « Conversations » avec une catégorie invalide | Le fil passe dans le filtre Conversations (NONE + messageCount > 1) |
| Compteurs des cartes WebaBox | Pouvaient afficher des compteurs fantômes | Compteurs exacts pour l'ensemble des 12 cartes |
1.5 Clarification clé — Architecture des 12 cartes WebaBox
Les 12 cartes WebaBox utilisent 5 valeurs en base de données + 7 filtres intelligents :
| Carte | Source |
|---|---|
| Urgent | webaCategory = URGENT |
| Important | webaCategory = IMPORTANT |
| Journal | webaCategory = JOURNAL |
| Bureau | webaCategory = OFFICE |
| Aucune | webaCategory = NONE ET messageCount = 1 |
| Conversations | webaCategory = NONE ET messageCount > 1 |
| Répondre plus tard | isReplyLater = true |
| Mis de côté | isSetAside = true |
| Suivis | isStarred = true |
| Indésirables | isSpam = true |
| Corbeille | deletedAt IS NOT NULL |
| Tous les courriels | Tous les fils non supprimés |
<a id="phase-b1"></a>
SECTION 2 : PHASE B.1 — BOUTON DE SUPPRESSION DE MIGRATION
2.1 Énoncé du problème
Le bouton Supprimer sur les cartes de projets de migration n'était visible que pour les statuts CREATED, COMPLETED, FAILED et CANCELLED. Les projets avec les statuts IMPORTING, SCANNING ou PLANNING n'affichaient aucun bouton Supprimer — laissant les utilisateurs dans l'impossibilité d'annuler une migration bloquée.
2.2 Modifications appliquées
Interface — app/(app)/migration/migration-client.tsx
// Avant
const canDelete = ['CREATED', 'COMPLETED', 'FAILED', 'CANCELLED'].includes(project.status);
// Après
const canDelete = ['CREATED', 'COMPLETED', 'FAILED', 'CANCELLED', 'IMPORTING', 'SCANNING', 'PLANNING'].includes(project.status);
Serveur — app/api/migration/projects/[id]/route.ts
// Avant
const deletableStatuses = ['CREATED', 'COMPLETED', 'FAILED', 'CANCELLED'];
// Après
const deletableStatuses = ['CREATED', 'COMPLETED', 'FAILED', 'CANCELLED', 'IMPORTING', 'SCANNING', 'PLANNING'];
2.3 Résultat
Les utilisateurs peuvent désormais supprimer des projets de migration dans n'importe quel statut, y compris les importations en cours.
<a id="phase-b2"></a>
SECTION 3 : PHASE B.2 — DÉCONNEXION DU COMPTE GOOGLE
Déjà présente dans la plateforme. Le bouton Déconnecter était fonctionnel sur la page Migration. Aucune modification requise.
<a id="phase-b3"></a>
SECTION 4 : PHASE B.3 — ENRICHISSEMENT AUTOMATIQUE LORS DE LA MIGRATION
4.1 Vue d'ensemble
Lorsque des contacts sont importés lors d'une migration Google Workspace, le système les enrichit automatiquement en :
- Créant/liant des enregistrements
CompanyContactselon le nom de l'entreprise ou le domaine du courriel - Créant des liens
ContactCompanyRoleentre Contact et CompanyContact - Analysant les signatures de courriels via un LLM pour extraire des données supplémentaires
4.2 Nouvelles fonctions
Fichier : lib/migration/migration-actions.ts
enrichContactPostCreation(contactId, normalizedContact, organizationId, userId)
- Déclencheur : Appelée en mode « fire-and-forget » après
createContactEntity()dans le flux d'exécution de la migration - Logique :
- Si
companyNameest présent → trouver ou créer unCompanyContact(correspondance par nom insensible à la casse OU domaine de courriel) - Extraire le domaine du courriel, ignorer les fournisseurs génériques (gmail, yahoo, hotmail, etc.)
- Créer un lien
ContactCompanyRoleavec le titre de poste comme rôle
- Si
- Gestion des erreurs : Mode « fire-and-forget » — les échecs sont consignés mais ne bloquent jamais la migration
analyzeSignatureWithLLM(bodyHtml, bodyText)
- Objectif : Extraire des données structurées à partir des signatures de courriels
- Modèle :
primary(gpt-4.1) via le wrapper LLM de WEBA - Champs extraits :
jobTitlecompanyNamephonewebsiteaddressbookingUrl← NOUVEAU (Calendly, Cal.com, HubSpot meetings, Acuity, etc.)
- Stratégie : Prend les 600 derniers caractères du corps du courriel comme bloc de signature
- Sortie : Réponse JSON analysée, retourne
nullsi aucune donnée utile n'est trouvée
4.3 Point d'intégration
Fichier : app/api/migration/projects/[id]/execute/route.ts
// Après createContactEntity()
enrichContactPostCreation(contact.id, normalized, organizationId, userId).catch(() => {});
<a id="phase-b4"></a>
SECTION 5 : PHASE B.4 — MOTEUR DE CLASSIFICATION WEBACATEGORY + ARCHIVAGE 90 JOURS
5.1 Moteur de classification
Fichier : lib/migration/weba-classify.ts
Classification basée sur des règles avec recours optionnel au LLM pour les fils ambigus.
Moteur de règles (sans coût LLM)
| Catégorie | Expressions régulières/Règles |
|---|---|
| JOURNAL | Rapports DMARC, noreply@, no-reply@, reçus, notifications d'expédition, confirmations de livraison, alertes système, réponses automatiques, messages de rebond |
| OFFICE | Infolettres, notifications de réseaux sociaux, courriels promotionnels, « unsubscribe », étiquettes de catégorie Gmail (CATEGORY_PROMOTIONS, CATEGORY_SOCIAL, CATEGORY_UPDATES, CATEGORY_FORUMS) |
| URGENT | Messages Gmail suivis, étiquette IMPORTANT |
| IMPORTANT | Contacts connus dans l'organisation (courriel présent dans la table ContactEmail), fils avec 3+ messages (conversations actives) |
| NONE | Valeur par défaut |
Recours au LLM (optionnel)
classifyAmbiguousWithLLM() — Classifie par lot les fils ayant obtenu NONE avec une faible confiance. Disponible pour une passe post-migration, mais non appelée lors de l'importation initiale afin de limiter les coûts.
5.2 Point d'intégration
Fichier : app/api/migration/projects/[id]/execute/route.ts
// Avant la création du fil
const webaCategory = classifyWebaCategory(threadData, gmailLabels, orgContactEmails);
// webaCategory transmise à EmailThread.create()
5.3 API d'archivage 90 jours
Fichier : app/api/migration/archive-old-threads/route.ts
- Point de terminaison :
POST /api/migration/archive-old-threads - Corps :
{ days?: number }(défaut : 90) - Action : Définit
isArchived: truesur les fils plus anciens que N jours - Audit : Consigné sous
migration.archive_old_threads
<a id="phase-c1"></a>
SECTION 6 : PHASE C.1 — ONGLET CHRONOLOGIE DU CONTACT
6.1 Nouvel onglet
Fichiers :
app/api/contacts/[id]/timeline/route.ts— Point de terminaison APIapp/(app)/contacts/[id]/timeline-tab.tsx— Composant d'interface
6.2 Fonctionnalités
- Liste chronologique de tous les échanges de courriels avec le contact
- Agrège l'ensemble des adresses courriel du contact (principale + enregistrements ContactEmail)
- Code couleur selon la direction :
- ENTRANT ↓ — Indicateurs verts
- SORTANT ↑ — Indicateurs bleus
- Affichage de l'objet, de l'extrait, de la date et des adresses d'expédition/réception
- Possibilité d'exportation en PDF
<a id="phase-c2"></a>
SECTION 7 : PHASE C.2 — ONGLET PIÈCES JOINTES (CODE COULEUR + APERÇU + PLEIN ÉCRAN)
7.1 Réécriture complète
Fichier : app/(app)/contacts/[id]/attachments-tab.tsx
7.2 Fonctionnalités
- Liste toutes les pièces jointes des courriels provenant des fils du contact
- Code couleur selon la direction : Badges verts pour ENTRANT, bleus pour SORTANT
- Bouton Aperçu (👁) : Ouvre une boîte de dialogue avec aperçu intégré pour :
- Images (tous formats)
- PDF (via iframe)
- Vidéo (lecteur HTML5)
- Audio (lecteur HTML5)
- Fichiers texte (affichage à espacement fixe)
- Mode plein écran (⛶) : Bouton Agrandir dans la boîte de dialogue d'aperçu → superposition noire immersive
- Bouton Télécharger : Disponible depuis la liste et la fenêtre modale d'aperçu
- API d'aperçu : Utilise le point de terminaison existant
/api/inbox/attachments/[id]?action=previewpour les URL présignées en ligne
<a id="phase-c3"></a>
SECTION 8 : PHASE C.3 — ONGLET JOURNAL DE FUSION
8.1 Nouvel onglet
Fichiers :
app/api/contacts/[id]/merge-log/route.ts— Point de terminaison APIapp/(app)/contacts/[id]/merge-log-tab.tsx— Composant d'interface
8.2 Fonctionnalités
- Affiche l'historique de toutes les opérations de fusion impliquant ce contact
- Affiche : date de fusion, contacts sources, acteur (qui a effectué la fusion)
- Données provenant des enregistrements AuditLog avec l'action
contact.merge
<a id="phase-c4"></a>
SECTION 9 : PHASE C.4 — ONGLET ANALYSE IA
9.1 Architecture
API : app/api/contacts/[id]/ai-insights/route.ts
Interface : app/(app)/contacts/[id]/ai-insights-tab.tsx
9.2 Analyse LLM
- Déclencheur : À la demande — l'utilisateur clique sur le bouton « Lancer l'analyse »
- Données recueillies : Détails du contact, toutes les adresses courriel, téléphones, rôles en entreprise, interactions récentes (objet + corps), notes
- Modèle :
primary(gpt-4.1) via le wrapper LLM de WEBA - Invite : Invite structurée en français demandant :
- Résumé de la relation
- Points clés de communication
- Statistiques d'interaction
- Recommandations
- Signaux de risque ou d'opportunité
9.3 Fonctionnalités de l'interface
- Bouton « Lancer l'analyse » avec style dégradé
- État de chargement avec indicateur animé
- Sections Markdown analysées (en-têtes, puces)
- Barre de statistiques : nombre de courriels, temps de réponse, jetons utilisés
- Bouton « Réanalyser » pour actualiser
- Couleur de l'onglet : Accent violet (cohérent avec les fonctionnalités IA)
<a id="phase-d"></a>
SECTION 10 : PHASE D — ENRICHISSEMENT PAR LOT ET VÉRIFICATION POST-MIGRATION
10.1 API d'enrichissement par lot
Fichier : app/api/migration/batch-enrich/route.ts
- Point de terminaison :
POST /api/migration/batch-enrich - Objectif : Enrichir les contacts sans
jobTitleNIcompanyNameen analysant leurs signatures de courriels - Flux :
- Trouver les contacts sans jobTitle/companyName (limite : 50-200 par lot)
- Pour chaque contact, trouver le dernier courriel ENTRANT (via lien de fil ou participantEmails)
- Appeler
analyzeSignatureWithLLM()sur le corps du courriel - Mettre à jour les champs du contact (jobTitle, companyName, website, calendarBookingUrl)
- Créer un enregistrement ContactPhone si un téléphone est extrait
- Créer CompanyContact + ContactCompanyRole si une entreprise est trouvée
- Déduplication : Vérifie les enregistrements existants avant de créer
- Audit : Consigné sous
migration.batch_enrich
10.2 API de vérification post-migration
Fichier : app/api/migration/post-verify/route.ts
- Point de terminaison :
POST /api/migration/post-verify - Objectif : Effectuer une vérification complète de l'état post-migration
- Retourne :
- Analyse des doublons : Utilise le
detectDuplicates()existant (correspondance par courriel, nom, téléphone) - Statistiques de complétude : Nombre de contacts sans jobTitle, companyName, téléphone, courriel
- Liens d'entreprise : Nombre de contacts associés à des CompanyContact
- Statistiques des fils : Total, archivés, distribution des WebaCategory
- Statistiques du projet : Si
projectIdest fourni, retourne le statut du projet de migration
- Analyse des doublons : Utilise le
- Audit : Consigné sous
migration.post_verify
<a id="phase-e"></a>
SECTION 11 : PHASE E — GESTIONNAIRE MULTI-CONTACTS
11.1 Vision
Un seul contact peut avoir :
- 4+ entreprises (via ContactCompanyRole → CompanyContact)
- 4+ numéros de téléphone (via enregistrements ContactPhone)
- 5-6 courriels (via enregistrements ContactEmail)
- Plusieurs adresses (via enregistrements ContactAddress — bureaux, propriétés, international)
- Plusieurs profils sociaux (via enregistrements ContactSocialMedia)
- URL de réservation (champ calendarBookingUrl)
11.2 Problème identifié
L'Intelligence de signature extrayait correctement les données, mais les enregistrait uniquement dans des champs plats :
| Donnée | Enregistrée dans (❌ Avant) | L'onglet lit depuis |
|---|---|---|
| Téléphone | Contact.primaryPhone (texte) | ContactPhone (table relationnelle) |
| Entreprise | Contact.companyName (texte) | ContactCompanyRole → CompanyContact (relations) |
| Facebook/Instagram | Contact.socialLinks (JSON) | ContactSocialMedia (table relationnelle) |
Résultat : Les onglets affichaient (0) malgré les données extraites.
11.3 Correction — E.1 : Enrichissement relationnel
Fichier : app/api/email/extract-signature/route.ts
L'API Signature Intel crée désormais des enregistrements relationnels en plus des champs plats :
Création de ContactPhone
- Crée un
ContactPhonepour lephoneextrait (étiquette : travail) et lemobilePhone(étiquette : mobile) - Définit
isPrimary: truepour le premier téléphone si le contact n'en a aucun - Déduplication : vérifie les enregistrements ContactPhone existants avant de créer
CompanyContact + ContactCompanyRole
- Trouve le CompanyContact existant par nom (insensible à la casse) ou domaine de courriel
- Crée un nouveau CompanyContact si introuvable (avec domaine, site web)
- Crée un lien ContactCompanyRole avec le titre de poste comme rôle/titre
- Définit
isPrimary: truepour le premier rôle en entreprise
ContactSocialMedia
- Crée des enregistrements individuels pour chaque plateforme sociale trouvée :
- LinkedIn →
LINKEDIN - Twitter/X →
TWITTER_X - Facebook →
FACEBOOK - Instagram →
INSTAGRAM - GitHub →
GITHUB - YouTube →
YOUTUBE - TikTok →
TIKTOK
- LinkedIn →
- Identifiant extrait de l'URL (supprime le protocole/www)
- Déduplication : vérifie la combinaison
plateforme:identifiant
11.4 Correction — E.2 : Déduplication lors de la fusion (ContactCompanyRole)
Fichier : lib/contacts/contact-merge.ts
Avant : updateMany déplaçait TOUS les enregistrements ContactCompanyRole → PLANTAGE sur la contrainte d'unicité contactId_companyContactId si la cible et la source partagent la même entreprise.
Après : Vérification par enregistrement :
// Pour chaque rôle source :
if (targetRoleSet.has(role.companyContactId)) {
// Même entreprise → supprimer le doublon de la source
await prisma.contactCompanyRole.delete({ where: { id: role.id } });
} else {
// Entreprise différente → déplacer vers la cible
await prisma.contactCompanyRole.update({ where: { id: role.id }, data: { contactId: targetId } });
}
11.5 Correction — E.3 : Déduplication lors de la fusion (ContactSocialMedia)
Fichier : lib/contacts/contact-merge.ts
Même approche — vérifie la combinaison plateforme:identifiant avant de déplacer :
if (targetSocialSet.has(`${s.platform}:${s.handle.toLowerCase()}`)) {
await prisma.contactSocialMedia.delete({ where: { id: s.id } });
} else {
await prisma.contactSocialMedia.update({ where: { id: s.id }, data: { contactId: targetId } });
}
11.6 Correction — E.4 : La cible hérite des meilleurs champs après la fusion
Fichier : lib/contacts/contact-merge.ts
Après la fusion, le contact cible hérite des meilleures données disponibles des sources fusionnées :
for (const source of sources) {
if (!target.jobTitle && source.jobTitle) updates.jobTitle = source.jobTitle;
if (!target.companyName && source.companyName) updates.companyName = source.companyName;
if (!target.website && source.website) updates.website = source.website;
if (!target.calendarBookingUrl && source.calendarBookingUrl) updates.calendarBookingUrl = source.calendarBookingUrl;
if (!target.socialLinks && source.socialLinks) updates.socialLinks = source.socialLinks;
}
11.7 Flux de fusion complet (16 étapes)
Lors de la fusion de N contacts en 1 cible :
| # | Relation | Stratégie |
|---|---|---|
| 1 | ContactEmail | Déplacer les non-doublons, supprimer les doublons |
| 2 | ContactPhone | Déplacer les non-doublons, supprimer les doublons |
| 3 | ContactInteraction | Tout déplacer |
| 4 | ContactNote | Tout déplacer |
| 5 | ContactTag | Déplacer les non-doublons, supprimer les doublons |
| 6 | ContactAddress | Tout déplacer |
| 7 | ContactSocialMedia | Déplacer les non-doublons, supprimer les doublons (E.3) |
| 8 | ContactCompanyRole | Déplacer les non-doublons, supprimer les doublons (E.2) |
| 9 | ContactGroupMember | Déplacer les non-doublons, supprimer les doublons |
| 10 | ContactObjectLink | Déplacer (ignorer les doublons via contrainte d'unicité) |
| 11 | FileAsset | Relier tous |
| 12 | ClientInvoice | Relier tous |
| 13 | EmailThread | Relier tous |
| 14 | StudioFormSubmission | Relier tous |
| 15 | ContractSignatory | Relier tous |
| 16 | CalendarEventAttendee | Relier tous |
Ensuite : définir mergedIntoId sur les sources, hériter des meilleurs champs sur la cible.
<a id="bugfixes"></a>
SECTION 12 : CORRECTIONS DE BOGUES
12.1 Onglet Chronologie — Boucle de chargement infinie
Cause racine : La fonction de traduction t de useT() était incluse dans les dépendances de useCallback. La référence de la fonction t change à chaque rendu, provoquant des boucles de récupération infinies.
Correction : Suppression de t du tableau de dépendances de useCallback dans timeline-tab.tsx.
12.2 Onglet Journal de fusion — Boucle de chargement infinie
Même cause racine et même correction que l'onglet Chronologie, dans merge-log-tab.tsx.
12.3 API de suppression — Statut IMPORTING bloqué
Problème : L'API du serveur refusait la suppression pour les projets avec les statuts IMPORTING/SCANNING/PLANNING.
Correction : Ajout de ces statuts au tableau deletableStatuses dans app/api/migration/projects/[id]/route.ts.
12.4 BookingUrl non extraite
Problème : analyzeSignatureWithLLM() n'extrayait pas les URL de réservation de calendrier.
Correction : Ajout de bookingUrl à l'invite LLM, à la signature de type, à la vérification hasData et à applyEnrichment(). Correspond à Contact.calendarBookingUrl.
<a id="files"></a>
SECTION 13 : FICHIERS MODIFIÉS — INVENTAIRE COMPLET
Nouveaux fichiers créés
| Fichier | Objectif |
|---|---|
lib/migration/weba-classify.ts | Moteur de classification WebaCategory (règles + LLM) |
app/api/migration/archive-old-threads/route.ts | API d'archivage des fils de 90 jours |
app/api/migration/batch-enrich/route.ts | API d'enrichissement par lot post-migration |
app/api/migration/post-verify/route.ts | API de vérification post-migration |
app/api/contacts/[id]/ai-insights/route.ts | API d'analyse Analyse IA |
app/(app)/contacts/[id]/ai-insights-tab.tsx | Composant d'interface Analyse IA |
Fichiers modifiés
| Fichier | Modifications |
|---|---|
app/(app)/webabox/webabox-client.tsx | Correction CONVERSATIONS → NONE |
app/(app)/migration/migration-client.tsx | Ajout de IMPORTING/SCANNING/PLANNING à canDelete |
app/api/migration/projects/[id]/route.ts | Ajout de IMPORTING/SCANNING/PLANNING à deletableStatuses |
app/api/migration/projects/[id]/execute/route.ts | Ajout des appels enrichContactPostCreation + classifyWebaCategory |
lib/migration/migration-actions.ts | Ajout de enrichContactPostCreation() + analyzeSignatureWithLLM() + bookingUrl |
app/(app)/contacts/[id]/timeline-tab.tsx | Correction de la boucle infinie (suppression de t des dépendances useCallback) |
app/(app)/contacts/[id]/merge-log-tab.tsx | Correction de la boucle infinie (suppression de t des dépendances useCallback) |
app/(app)/contacts/[id]/attachments-tab.tsx | Réécriture complète : fenêtre modale d'aperçu + plein écran |
app/(app)/contacts/[id]/contact-detail-client.tsx | Ajout de l'onglet Analyse IA |
app/api/email/extract-signature/route.ts | Ajout de l'enrichissement relationnel (ContactPhone, CompanyContact, ContactSocialMedia) |
lib/weba/signature-extraction.ts | Référence — buildContactEnrichmentData (inchangé) |
lib/contacts/contact-merge.ts | E.2/E.3 : déduplication ContactCompanyRole + ContactSocialMedia ; E.4 : héritage des meilleurs champs |
<a id="checkpoints"></a>
SECTION 14 : CHRONOLOGIE DES POINTS DE CONTRÔLE
| # | Point de contrôle | Description |
|---|---|---|
| 1 | Correction Phase A | URGENT → NONE (et non CONVERSATIONS) dans webabox-client.tsx |
| 2 | Phase B.1-B.2 | Bouton Supprimer visible + Déconnexion Google (préexistant) |
| 3 | Phase C.1-C.3 | Onglets Chronologie, Pièces jointes (code couleur), Journal de fusion |
| 4 | Correction suppression chronologie journalfusion aperçu | Suppression IMPORTING + corrections boucles infinies + aperçu/plein écran Pièces jointes |
| 5 | Onglet C.4 Analyse IA contacts | Onglet d'analyse LLM à la demande |
| 6 | B.3 enrichissement auto CompanyContact migration | Enrichissement automatique lors de l'exécution de la migration |
| 7 | B.4 classification WebaCategory archivage 90j | Moteur de classification + API d'archivage |
| 8 | API D enrichissement-lot vérification-post | Points de terminaison d'enrichissement par lot + vérification |
| 9 | Correction API suppression autoriser statut IMPORTING | Correction de l'API du serveur pour la suppression IMPORTING |
| 10 | Ajout extraction bookingUrl depuis signatures | BookingUrl ajoutée à l'extraction de signature LLM |
| 11 | E enrichissement relationnel multi-contacts fusion | Enrichissement relationnel + déduplication lors de la fusion |
SECTION 15 : IMPACT SUR LE SCHÉMA
Zéro modification du schéma
Toutes les modifications utilisent des modèles et des champs Prisma existants :
Contact— jobTitle, companyName, website, calendarBookingUrl, socialLinks, primaryPhone, primaryEmailContactPhone— phone, label, isPrimaryContactEmail— email, isPrimaryContactCompanyRole— contactId, companyContactId, role, title, isPrimaryCompanyContact— name, domain, website, organizationIdContactSocialMedia— platform (énumération SocialPlatform), handle, url, isPrimaryContactAddress— champs d'adresse completsEmailThread— webaCategory (énumération WebaCategory), isArchivedContactInteraction— subject, bodyContactNote— content
Aucun prisma db push requis. Aucun --force-reset. Aucun --accept-data-loss.
SECTION 16 : POINTS DE TERMINAISON API CRÉÉS
| Méthode | Point de terminaison | Objectif |
|---|---|---|
| POST | /api/migration/batch-enrich | Enrichissement par lot des contacts sans jobTitle/companyName via analyse LLM des signatures de courriels |
| POST | /api/migration/post-verify | Vérification post-migration (doublons + statistiques de complétude) |
| POST | /api/migration/archive-old-threads | Archiver les fils plus anciens que N jours (défaut : 90) |
| POST | /api/contacts/[id]/ai-insights | Analyse LLM à la demande de la relation avec le contact |
SECTION 17 : ONGLETS DU DÉTAIL DU CONTACT (LISTE COMPLÈTE)
Rangée 1
| Onglet | Source de données |
|---|---|
| Vue d'ensemble | ContactForm (champs modifiables) |
| Entreprises | ContactCompanyRole → CompanyContact |
| Courriel | Enregistrements ContactEmail |
| Téléphone | Enregistrements ContactPhone |
| Adresses | Enregistrements ContactAddress |
| Réseaux sociaux | Enregistrements ContactSocialMedia |
Rangée 2
| Onglet | Source de données |
|---|---|
| Activité | Enregistrements ContactInteraction |
| Notes | Enregistrements ContactNote |
| Étiquettes | ContactTag → Tag |
| Calendrier | CalendarEvent (via participants) |
| Signature Intel | Extraction LLM depuis les courriels entrants |
| Chronologie | Agrégation EmailMessage (NOUVEAU) |
| Journal de fusion | AuditLog avec action=contact.merge (NOUVEAU) |
| Pièces jointes | EmailAttachment avec aperçu/plein écran (RÉÉCRIT) |
| Analyse IA | Analyse LLM à la demande (NOUVEAU) |
| Contrats | Enregistrements ContractSignatory |
Fin de l'Addendum 06
« Une seule WEBA. Chaque canal. En temps réel, toujours. »
Document préparé par : Agent de développement WEBA
Validé par : Alain Bessette
Date : 6 juin 2026
Classification : Interne — Spécification technique