Automatisation FIFPL (sous le capot)
Le module FIFPL automatise une tâche autrement manuelle et fastidieuse : récupérer la liste officielle des participants depuis le portail FIFPL, la rapprocher des transactions HubSpot, puis propager les noms et montants corrects dans HubSpot — d’où ils redescendent vers l’internal-api. Tout est déclenché par l’opérateur depuis l’interface ; cette page décrit chaque maillon.
Vue d’ensemble
Section intitulée « Vue d’ensemble »exportParticipants (Puppeteer → of.fifpl.fr → XLSX → lignes typées) ↓matchParticipantRows (worker Claude Code ; sinon repli déterministe) ↓buildFifplSyncUpdates (diff par champ ; ignore les deals déjà à jour) ↓syncFifplParticipantNames (batch HubSpot 100 par 100, idempotent) ↓confirmFifplSync (polling internal-api jusqu'à propagation du webhook) ↓[CV-12H] splitFIFPLVirtualClassModules (découpe la classe virtuelle 12 h en 4 demi-journées)1. Export depuis le portail FIFPL
Section intitulée « 1. Export depuis le portail FIFPL »Procédure tRPC exportParticipants. Entrée : le NACPRO (référence financeur) + la date de fin de
session. Elle appelle le puppeteer-service avec le script fifpl-extract-participants-obscura
(Chromium furtif, pour réduire les blocages anti-bot), qui se connecte à of.fifpl.fr, navigue
jusqu’au dossier et télécharge l’XLSX.
L’XLSX est ensuite parsé avec ExcelJS, de façon tolérante aux variations d’en-têtes : les colonnes sont reconnues par alias normalisés —
- nom :
nom,nom usuel,nom d'usage,nom marital,nom de famille… - prénom :
prenom,prenoms - nom de naissance :
nom de naissance,nom de jeune fille…
Les dates (série Excel, JJ/MM/AAAA, AAAA-MM-JJ) et les montants français (1 234,56 €) sont
normalisés.
Stratégie de réessai
Section intitulée « Stratégie de réessai »L’export distingue les erreurs déterministes (mauvais NACPRO, identifiants invalides, schéma XLSX changé, HTTP 403 résiduel…) — qui échouent immédiatement car réessayer ne sert à rien — des erreurs transitoires (OOM Chromium, aléa réseau, hoquet du portail) — pour lesquelles un seul réessai est tenté (2 tentatives au total).
2. Appariement des participants (Claude Code)
Section intitulée « 2. Appariement des participants (Claude Code) »Procédure tRPC matchParticipantRows. L’appariement nom-à-nom est piégeux : prénoms/noms inversés,
accents, traits d’union, noms composés, noms de naissance. Plutôt qu’une heuristique fragile, l’app
délègue à un worker Claude Code :
- Les candidats (transactions HubSpot) sont découpés en lots de 50 (
MATCH_CHUNK_SIZE), chaque lot voyant toutes les lignes XLSX (l’appariement reste correct). - Jusqu’à 4 lots tournent en parallèle (
MATCH_CONCURRENCY). - Chaque lot a un délai maximal de 180 s (
DEFAULT_TIMEOUT_MS) — suffisant pour de grosses sessions (~400 participants). - Le worker renvoie, par candidat, le meilleur
rowIndex(ounull), un score de confiance, le champ d’appariement et une justification ; la réponse est extraite du flux SSE puis validée par Zod.
3. Synchronisation HubSpot idempotente
Section intitulée « 3. Synchronisation HubSpot idempotente »Procédure tRPC syncFifplParticipantNames. Le cœur de la robustesse :
- Pré-filtrage :
buildFifplSyncUpdatesignore les transactions dont l’état HubSpot possède déjà toutes les valeurs que la ligne pousserait (via le gardefifplDealUpToDate). - Lecture de l’état courant : lecture par lot des contacts et deals HubSpot, 100 par
lot (
BATCH_LIMIT, limite de l’API HubSpot). - Diff par champ : on ne calcule que les propriétés qui diffèrent (si un même contact/deal apparaît dans plusieurs mises à jour, les diffs sont fusionnés — la dernière écriture gagne par propriété, chaque id n’apparaît qu’une fois).
- Écriture par lot : mise à jour uniquement des ids au diff non vide, 100 par lot. Un lot en échec est enregistré (avec ses ids et le message HubSpot) mais n’interrompt pas les autres — pas de rollback. L’UI montre quels deals/contacts ont échoué et pourquoi.
Champs écrits — contacts : fifpl_first_name, fifpl_last_name, maiden_name,
date_of_birth ; deals : fifpl_firstname, fifpl_lastname, amount.
4. Confirmation par propagation
Section intitulée « 4. Confirmation par propagation »État machine confirmingFifplSync. La descente HubSpot → internal-api est asynchrone (pilotée
par un webhook). L’app interroge donc l’internal-api en boucle (re-fetch des sessions par
crmId) jusqu’à ce que les noms attendus apparaissent côté session (prédicat nameFieldsMatch).
En cas de timeout, la machine passe en état d’attente offrant à l’opérateur de réessayer ou ignorer ; les dossiers non confirmés sont listés. Aucune étape suivante ne démarre tant que la propagation n’est pas confirmée.
5. Découpage CV-12H
Section intitulée « 5. Découpage CV-12H »Après la synchro des noms, si toutes les sessions financées requièrent le découpage CV-12H,
l’app récupère la classe virtuelle du dossier et appelle splitFIFPLVirtualClassModules : une
classe virtuelle de 12 h est découpée en 4 demi-journées (exigence FIFPL), via la logique
partagée buildFIFPLVirtualClass12HSplitModules.
Sous le capot
Section intitulée « Sous le capot »- Contrôleurs tRPC :
librairies/trpc/src/controller/fifpl/index.ts(exportParticipants,matchParticipantRows),fifpl/fifpl-client.ts(Puppeteer + parsing XLSX, alias d’en-têtes, classification d’erreurs),fifpl/worker-client.ts(worker Claude, SSE, timeout 180 s). - Synchro HubSpot :
librairies/trpc/src/controller/billing/index.ts(syncFifplParticipantNames,BATCH_LIMIT = 100, lecture/diff/écriture par lot). - Appariement / idempotence :
applications/billing/src/machines/fifpl-row-matcher.ts(buildFifplSyncUpdates,applyFifplMatches,fifplDealUpToDate,nameFieldsMatch) ; logique de noms partagéelibrairies/business-logic-shared/src/fifpl/name-matcher.ts. - Constantes clés :
MATCH_CHUNK_SIZE = 50,MATCH_CONCURRENCY = 4,DEFAULT_TIMEOUT_MS = 180_000,BATCH_LIMIT = 100, export FIFPL = max 2 tentatives. - Découpage CV-12H :
librairies/trpc/src/controller/virtual-class/index.ts(splitFIFPLVirtualClassModules). - Propriétés HubSpot : voir
librairies/business-logic-shared/src/hubspot/index.ts.