AACsearch
Architektur

Konnektor-Lebenszyklus

Die sechs Konnektor-Operationen — Handshake, Heartbeat, Full-Sync, Delta-Sync, Delete, Diagnose — und wie sie auf die Connector-API-Oberfläche abgebildet werden.

Ein CMS-Konnektor (PrestaShop, Bitrix, WordPress, Shopify) spricht mit AACsearch nur über die Connector-API, die unter /api/connectors/** und /api/projects/:projectId/** montiert ist. Er fasst Typesense nie direkt an. Jeder Aufruf wird durch ein ss_connector_*-Token mit dem Scope connector_write gegated.

Lebenszyklus

Beschreibung

Das Diagramm durchläuft die sechs CMS-Connector-Phasen — Handshake, Heartbeat, Full-Sync, Delta-Sync, Delete, Diagnostics — jede gegated durch ein ss_connector_*-Token. Sync-Aufrufe erzeugen eine SearchConnectorSyncJob-Zeile plus N SearchSyncOutbox-Zeilen; der Worker leert das Outbox in den Typesense-Alias, während das CMS-Modul die jobId auf Fertigstellung pollt.

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 }
    end

Die sechs Operationen

PhaseHTTPBody-CapZweckPersistiert
HandshakePOST /api/connectors/handshakekleinToken bestätigen, Capabilities + Sync-Modi austauschenAktualisiert lastUsedAt
HeartbeatPOST /api/connectors/:connectorId/heartbeatkeinerModul-Lebens-Ping, Server-Zeit-AustauschAktualisiert lastUsedAt
Full-SyncPOST /api/projects/:projectId/sync/full1000Erstlast oder Reset; Bulk-Upsert des ganzen KatalogsSearchConnectorSyncJob + Outbox-Zeilen
Delta-SyncPOST /api/projects/:projectId/sync/delta100Per-Change-Webhook aus dem CMSSearchConnectorSyncJob + Outbox-Zeilen
DeleteDELETE /api/projects/:projectId/products/:externalId
DELETE /api/connector/documents
1 / 500Ein Produkt / Batch entfernendoc_delete-Outbox-Zeile(n)
DiagnosePOST /api/projects/:projectId/diagnostics4 KBSelbstreport: PHP-Version, letzter Sync, Error-LogIn-Memory-Diagnostik-Store + strukturiertes Log

Was jeden Aufruf gated

gateConnectorRequest läuft vor jeder Handler-Logik:

  1. Authorization-Header muss Bearer ss_connector_* tragen.
  2. verifySearchApiKey(rawKey, "connector_write") — Admin-Scope ist eine Übermenge.
  3. Liefert { keyId, organizationId, indexId, indexSlug } an den Handler.
  4. Sync-Handler prüfen zusätzlich, dass :projectId mit organizationId übereinstimmt — sonst 404, falls ein Token gegen ein anderes Projekt verwendet wird.

Warum Job + Outbox

Die Connector-API blockiert nie auf Typesense. executeSyncJob schreibt eine SearchConnectorSyncJob-Zeile für End-to-End-Sichtbarkeit plus N Zeilen in SearchSyncOutbox, die der Worker drainiert. Das CMS-Modul erhält eine jobId, die es zum Pollen verwenden kann; der Worker versöhnt jede Zeile unabhängig, sodass eine einzelne fehlerhafte SKU den Batch nicht bricht.

Verwandt

On this page