Ruta de escritura
Cómo una escritura de documento entra en AACsearch — desde POST /v1/indexes/.../documents a través de SearchIngestBuffer / SearchSyncOutbox y el worker, hasta el alias de Typesense.
AACsearch es DB-first: cada escritura aterriza primero en PostgreSQL antes de proyectarse a Typesense. La capa HTTP nunca llama a Typesense de forma síncrona desde una petición de cliente. Esto es la Hard Invariant #2 — durabilidad, manejo de fallos parciales y reindex sin tiempo de inactividad dependen de ello.
Flujo
Descripción
El diagrama muestra una escritura HTTP síncrona desde el cliente que es autenticada, limitada por rate-limit y verificada contra cuota, para luego encolarse de forma durable en PostgreSQL (SearchIngestBuffer / SearchSyncOutbox) — el cliente recibe 202 Accepted de inmediato. Un worker en segundo plano reclama después las filas pendientes, adjunta embeddings e importa el batch al alias de Typesense, reconciliando éxito o fallo por fila con backoff exponencial.
sequenceDiagram
autonumber
participant Client as Customer / Connector
participant API as packages/api/v1/documents.ts
participant Auth as verifySearchApiKey (scope=ingest)
participant DB as PostgreSQL (SearchIngestBuffer + SearchSyncOutbox)
participant W as Sync worker (sync-worker.ts)
participant Embed as autoEmbedDocuments
participant TS as Typesense alias_name(orgShortId_slug)
Client->>API: POST /v1/indexes/:indexId/documents:batch
API->>Auth: Bearer ss_search_* / ss_connector_*
Auth-->>API: VerifiedSearchKey { organizationId, indexId }
API->>API: rate-limit (per-key, 1m sliding bucket)
API->>API: enforceQuota (plan / overage)
API->>DB: enqueueManySearchIngest() (or SearchSyncOutbox doc_upsert)
API-->>Client: 202 Accepted (jobId)
loop worker tick
W->>DB: claim pending rows (atomic updateMany + lockedBy)
W->>Embed: autoEmbedDocuments(batch)
Embed-->>W: vectors attached
W->>TS: collection.documents().import(batch, action=upsert)
alt all green
W->>DB: markIngestRowsSuccess / outbox.status=done
else partial fail
W->>DB: markIngestRowsFailure + nextRetryAt (exp. backoff)
end
endQué garantiza cada paso
- Auth (
verifySearchApiKey). El token se hashea (sha256) y se compara contra la columnaSearchApiKey.hash. Las claves de conector (ss_connector_*) y de búsqueda (ss_search_*) comparten espacio de hash; la columnascopesdirige la autorización. - Rate limit. Ventana deslizante por clave desde
SearchRateLimitBucket. SobrepasarrateLimitPerMinutedevuelve 429 antes de cualquier escritura en BD. - Gate de cuota. Los entitlements del plan y el overage de wallet se comprueban una vez por petición; la cuota de escritura se consume atómicamente con el enqueue.
- Enqueue durable. Las filas se escriben en
SearchIngestBuffer(ruta legacy) oSearchSyncOutbox(ruta canónica, idempotente). La respuesta HTTP es202— el documento no necesita estar en Typesense antes de que el cliente reciba la respuesta. - Proyección del worker. Un proceso en segundo plano reclama filas con
lockedBy = WORKER_ID, ejecuta auto-embedding cuando el índice tiene un campo vectorial, llama acollection.documents().import()y reconcilia éxito / fallo por fila. - Destino del alias. El worker siempre escribe en
aliasName(organizationId, slug), que apunta a la versión física actual de la colección. El reindex intercambia el alias de forma atómica; las escrituras en vuelo siguen el nuevo puntero.
Por qué DB-first
- Durabilidad. Reinicios del servidor o caídas de Typesense no pierden escrituras.
- Recuperación de fallos parciales. Solo se reintentan las filas fallidas; las exitosas no se duplican.
- Aislamiento de tenants. El worker etiqueta cada documento con el campo
tenantIdantes del import; el alias imponefilter_byen lectura. - Backpressure. El buffer absorbe full-syncs ráfaga del CMS sin sobrecargar Typesense.
Relacionado
- Ciclo de vida del conector — cómo los módulos de CMS alimentan esta misma ruta de escritura.
- Ruta de lectura — el flujo espejo para consultas.
- Reindex y zero-downtime — mecánica del intercambio de alias.
Arquitectura
Referencia visual para las entrañas de AACsearch — ruta de escritura, ruta de lectura, modelo de seguridad, ciclo de vida del conector y el bucle de feedback analítico.
Ruta de lectura
Cómo una consulta de búsqueda fluye por AACsearch — desde el SDK del cliente hasta /search/public/multi, pasando por public-auth y la combinación de filtro de tenant, hacia el multi_search de Typesense y de vuelta como respuesta saneada.