AACsearch
Архитектура

Жизненный цикл коннектора

Шесть операций коннектора — handshake, heartbeat, full-sync, delta-sync, delete, диагностика — и их соответствие поверхности Connector API.

CMS-коннектор (PrestaShop, Bitrix, WordPress, Shopify) общается с AACsearch только через Connector API, смонтированный по /api/connectors/** и /api/projects/:projectId/**. Он никогда не обращается к Typesense напрямую. Каждый вызов гейтится токеном ss_connector_* со scope connector_write.

Жизненный цикл

Описание

Диаграмма проходит шесть фаз CMS-коннектора — handshake, heartbeat, full-sync, delta-sync, delete, диагностика — каждая гейтится токеном ss_connector_*. Sync-вызовы создают строку SearchConnectorSyncJob плюс N строк SearchSyncOutbox; воркер сливает outbox в alias Typesense, а CMS-модуль поллит jobId до завершения.

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

Шесть операций

ФазаHTTPЛимит телаНазначениеСохраняет
handshakePOST /api/connectors/handshakeмалыйПодтвердить токен, обменяться capabilities + modesОбновляет lastUsedAt
heartbeatPOST /api/connectors/:connectorId/heartbeatпустоПинг живости модуля, обмен серверным временемОбновляет lastUsedAt
full-syncPOST /api/projects/:projectId/sync/full1000Первичная загрузка или сброс; bulk-upsert каталогаSearchConnectorSyncJob + строки outbox
delta-syncPOST /api/projects/:projectId/sync/delta100Webhook на изменение из CMSSearchConnectorSyncJob + строки outbox
deleteDELETE /api/projects/:projectId/products/:externalId
DELETE /api/connector/documents
1 / 500Удалить один продукт / партиюСтрока(и) outbox doc_delete
диагностикаPOST /api/projects/:projectId/diagnostics4 КБСамоотчёт о версии PHP, последнем sync, ошибкахIn-memory хранилище диагностики + структурный лог

Что гейтит каждый вызов

gateConnectorRequest выполняется до любой логики handler-а:

  1. Заголовок Authorization должен нести Bearer ss_connector_*.
  2. verifySearchApiKey(rawKey, "connector_write") — admin-scope является надмножеством.
  3. Возвращает { keyId, organizationId, indexId, indexSlug } для handler-а.
  4. Sync-handler-ы дополнительно проверяют, что :projectId совпадает с organizationId — иначе возвращается 404, если токен используется против другого проекта.

Зачем job + outbox

Connector API никогда не блокируется на Typesense. executeSyncJob пишет строку SearchConnectorSyncJob для сквозной видимости плюс N строк в SearchSyncOutbox, которые сливает воркер. CMS-модуль получает jobId, который можно опрашивать; а воркер согласует каждую строку независимо, поэтому одна плохая SKU не ломает весь batch.

См. также

On this page