Écrit par une IA. Ce projet a été développé par Claude Code (Anthropic), un agent IA, pour le compte de TEMPILO. Les commits portent la mention
Co-Authored-Bycorrespondante.
Synchronisation bidirectionnelle des contacts entre Google Contacts et
Twenty CRM, avec une page native intégrée dans Twenty. Le service héberge
aussi des fonctions annexes ajoutées ensuite : synchro Google Agenda ↔
Tâches Twenty, autocomplétion d'adresse, et un secours de récupération du
contenu complet des e-mails IMAP pour Tempilo Mail (voir server.js pour le
détail des routes de ces extensions).
- Google → Twenty : tous les contacts Google sont comparés à la base Twenty. Un contact absent est créé. Un contact déjà présent (même email, même téléphone ou même nom complet) n'est jamais recréé — seuls les champs vides sont complétés, une valeur déjà renseignée n'est jamais écrasée.
- Twenty → Google : uniquement les personnes qui sont point de contact d'au moins une opportunité (pas toute la base Twenty). Même règle de non-écrasement.
- La comparaison utilise, dans l'ordre : email, téléphone,
contactEmail/contactPhonede l'opportunité liée (un champ Twenty séparé de la fiche Personne), puis le nom complet (prénom+nom) en dernier recours. - Deux modes : synchro complète (tout, plus lent) et ⚡ 50 derniers contacts (recherche ciblée, rapide, pour un rattrapage quotidien).
- Synchro automatique 2x/jour, à un horaire aléatoire, toujours en dehors de 7h-19h (heure de Paris, changement d'heure géré automatiquement).
- Réservé aux administrateurs Twenty (vérifié côté serveur, pas seulement côté interface).
- Seuil de sécurité : une synchro automatique s'arrête d'elle-même au-delà de 20 actions et attend une vérification manuelle.
- Historique des 50 dernières synchros, avec le détail (nom, action) de chaque contact créé ou modifié.
Deux parties déployées séparément :
- Ce dossier (
app/) — un service Node.js/Express autonome (server.js), conteneurisé, qui parle à l'API Google People et à l'API REST/GraphQL de Twenty. Exposé en interne sur le port3001, routé par Caddy surhttps://sync.tempilo.eu. /mnt/data/tempilo/apps/tempilo-google-contacts/— une vraie application native Twenty (frameworkcreate-twenty-app), qui affiche la page "Google Contacts Sync" dans le menu latéral de Twenty. Cette page appelle ce service via de simples requêtes HTTP.
PORT=3001
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
GOOGLE_REDIRECT_URI=https://sync.tempilo.eu/auth/google/callback
TWENTY_API_URL=http://twenty-server-1:3000
TWENTY_API_KEY=...
TWENTY_API_URLdoit pointer vers le nom du conteneur Twenty sur le réseau Docker interne (http://twenty-server-1:3000), pas l'URL publiquehttps://crm.tempilo.eu— sinon le conteneur boucle sur l'IP publique du serveur et time-out (bug rencontré et corrigé le 2026-08-26).GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET: identifiants OAuth d'un projet Google Cloud avec l'API People activée.TWENTY_API_KEY: une clé API Twenty avec accès en lecture/écriture sur les objets Personne, Entreprise, Opportunité.
Les jetons Google (après connexion via /auth/google) sont stockés dans
data/google-tokens.json, jamais dans .env. L'historique des synchros
est dans data/sync-history.json. Le dossier data/ est monté en volume
Docker et ne doit jamais être versionné (contient des secrets).
docker compose up -d --buildPuis se connecter une première fois à Google via https://sync.tempilo.eu/auth/google
(flow OAuth classique, à faire une seule fois — les jetons se renouvellent
seuls ensuite).
| Route | Méthode | Description |
|---|---|---|
/health |
GET | État courant (connecté, synchro en cours, dernier résultat) |
/sync?mode=recent |
POST | Lance une synchro (mode=recent = 50 derniers, sinon complète). Nécessite { userId } dans le corps, doit être un administrateur Twenty. |
/sync/cancel |
POST | Interrompt la synchro en cours. Même restriction admin. |
/sync/history |
GET | Les 50 dernières synchros (résumé + détail des actions) |
/is-admin?userId= |
GET | Indique si cet utilisateur Twenty est administrateur |
/auth/google |
GET | Démarre la connexion OAuth Google |
- Toute action de création/modification est protégée côté serveur par une vérification du rôle Administrateur Twenty (pas seulement un bouton grisé côté interface — un appel direct à l'API est aussi bloqué).
- CORS ouvert (
Access-Control-Allow-Origin: *) sur ce service : la page Twenty qui l'appelle tourne dans un cadre isolé (sandbox) dont l'origine réseau varie, une liste blanche stricte bloquait les appels légitimes. Aucune donnée sensible n'est exposée par cette API sans le contrôle admin déjà décrit.
Construit et durci le 2026-08-25/26. Un incident de doublons (contacts sans email/téléphone recréés à chaque synchro faute de correspondance possible) a été détecté, corrigé (ajout d'une comparaison par nom complet en dernier recours) et nettoyé (124 doublons supprimés) le 2026-08-26.