Cycle de vie du connecteur
Les six opérations du connecteur — handshake, heartbeat, full-sync, delta-sync, delete, diagnostics — et leur mapping sur la surface de la Connector API.
Un connecteur CMS (PrestaShop, Bitrix, WordPress, Shopify) ne parle à AACsearch qu'à
travers la Connector API montée sur /api/connectors/** et
/api/projects/:projectId/**. Il ne touche jamais Typesense directement. Chaque
appel est gated par un token ss_connector_* ayant le scope connector_write.
Cycle de vie
Description
Le diagramme parcourt les six phases du connecteur CMS — handshake, heartbeat, full-sync, delta-sync, delete, diagnostics — chacune gated par un token ss_connector_*. Les appels de sync créent une ligne SearchConnectorSyncJob plus N lignes SearchSyncOutbox ; le worker draine l'outbox vers l'alias Typesense pendant que le module CMS poll la jobId jusqu'à la complétion.
sequenceDiagram
autonumber
participant Mod as CMS module (PrestaShop / Bitrix / WP / Shopify)
participant API as packages/api/modules/search/connector-public.ts
participant Auth as gateConnectorRequest (scope=connector_write)
participant DB as PostgreSQL (SearchConnectorSyncJob + SearchSyncOutbox)
participant W as Sync worker
participant TS as Typesense alias
rect rgb(220, 252, 231)
note over Mod,API: Phase 1 — handshake (once per install)
Mod->>API: POST /api/connectors/handshake { moduleVersion, platform }
API->>Auth: verify ss_connector_* + connector_write
API-->>Mod: { projectId, indexSlug, capabilities, syncModes }
end
rect rgb(219, 234, 254)
note over Mod,API: Phase 2 — heartbeat (periodic, every ~5 min)
Mod->>API: POST /api/connectors/:connectorId/heartbeat
API-->>Mod: { status: "ok", timestamp }
end
rect rgb(254, 243, 199)
note over Mod,DB: Phase 3 — full sync (initial / on-demand)
Mod->>API: POST /api/projects/:projectId/sync/full { products[1..1000] }
API->>DB: createSyncJob(type=full)
API->>DB: executeSyncJob -> enqueue doc_upsert per product (outbox)
API-->>Mod: { jobId, total, queued }
W->>DB: drain outbox doc_upsert rows
W->>TS: bulkUpsert(batch, action=upsert)
W->>DB: completeSyncJob(jobId)
end
rect rgb(245, 243, 255)
note over Mod,DB: Phase 4 — delta sync (per change webhook)
Mod->>API: POST /api/projects/:projectId/sync/delta { products[1..100] }
API->>DB: createSyncJob(type=delta)
API->>DB: executeSyncJob -> outbox rows
API-->>Mod: { jobId, total, queued }
W->>TS: bulkUpsert(batch)
end
rect rgb(254, 226, 226)
note over Mod,TS: Phase 5 — delete (single or batch)
Mod->>API: DELETE /api/projects/:projectId/products/:externalId
API->>DB: enqueue doc_delete
W->>TS: delete_by_query(externalId)
Mod->>API: DELETE /api/connector/documents { externalIds[1..500] }
API->>DB: enqueue doc_delete (batch)
W->>TS: batch delete
end
rect rgb(241, 245, 249)
note over Mod,DB: Phase 6 — diagnostics (on demand / on error)
Mod->>API: POST /api/projects/:projectId/diagnostics { moduleVersion, lastFullSync, errors[] }
API->>DB: recordDiagnostics() (in-memory store + log)
API-->>Mod: { received: true }
endLes six opérations
| Phase | HTTP | Cap. body | Rôle | Persiste |
|---|---|---|---|---|
| handshake | POST /api/connectors/handshake | petit | Confirmer le token, échanger capabilities + modes | Met à jour lastUsedAt |
| heartbeat | POST /api/connectors/:connectorId/heartbeat | aucun | Ping de vie du module, échange d'heure serveur | Met à jour lastUsedAt |
| full-sync | POST /api/projects/:projectId/sync/full | 1000 | Premier chargement / reset ; bulk-upsert du catalogue entier | SearchConnectorSyncJob + lignes outbox |
| delta-sync | POST /api/projects/:projectId/sync/delta | 100 | Webhook par changement venant du CMS | SearchConnectorSyncJob + lignes outbox |
| delete | DELETE /api/projects/:projectId/products/:externalIdDELETE /api/connector/documents | 1 / 500 | Supprimer un produit / lot | Ligne(s) outbox doc_delete |
| diagnostics | POST /api/projects/:projectId/diagnostics | 4 Ko | Auto-rapport version PHP, dernier sync, log d'erreurs | Store de diagnostics en mémoire + log structuré |
Ce qui gate chaque appel
gateConnectorRequest s'exécute avant toute logique de handler :
- L'en-tête Authorization doit porter
Bearer ss_connector_*. verifySearchApiKey(rawKey, "connector_write")— le scope admin est un superset.- Renvoie
{ keyId, organizationId, indexId, indexSlug }au handler. - Les handlers de sync vérifient en plus que
:projectIdcorrespond àorganizationId— 404 est renvoyé si un token est utilisé contre un autre projet.
Pourquoi un job + une outbox
La Connector API ne bloque jamais sur Typesense. executeSyncJob écrit une ligne
SearchConnectorSyncJob pour la visibilité de bout en bout, plus N lignes dans
SearchSyncOutbox que le worker draine. Le module CMS reçoit un jobId qu'il peut
poller pour suivre la complétion ; le worker réconcilie chaque ligne
indépendamment, donc une SKU mauvaise ne casse pas le lot entier.
Liens associés
- Chemin d'écriture — le côté worker de l'outbox.
- Types de clés et modèle de sécurité
— forme et règles de scope du token
ss_connector_*.
Types de clés et modèle de sécurité
Les quatre catégories de clés AACsearch — search, connector, scoped et admin — leurs préfixes ss_*, leur stockage en hash uniquement, le HMAC + TTL + filtre des scoped tokens et la manière dont chacune est vérifiée à la requête.
Boucle de feedback analytique
Comment une requête de recherche devient un SearchUsageEvent, comment les clics et conversions sont enregistrés, et comment l'agrégation alimente le tableau de bord pour l'ajustement de pertinence.