Skip to content

Search

@nx/search is a library package, not a standalone IGNIS application. It ships four IGNIS components that a host service (currently commerce) registers, plus a SearchableControllerMixin consumers wire onto their own REST controllers. It keeps ~8 Typesense collections in sync with PostgreSQL via a Debezium → Kafka CDC pipeline and serves keyword + optional semantic search.

1. Quick Reference

PropertyValue
Package@nx/search
CodeLIB-SEARCH
TypeLibrary / component package (consumed by commerce)
RuntimeBun (>=1.3.8) — runs inside the host process
Base ClassN/A — no Application class; exports BaseComponent subclasses
Locationpackages/search
Base Path/search (mounted under the host service's base path)
Dev PortN/A — library package, no port of its own
Container PortN/A — runs in the host container (commerce)
Snowflake IDN/A — host service owns ID allocation
Search EngineTypesense ^3.0.3 (nodes as protocol:host:port)
Sync SourceDebezium → Kafka CDC (public, pricing, inventory schemas)
Consumed bycommerce
Binding Namespace@nx/search

Library nature: there is no application.ts, index.ts → bootstrapApplication(), dedicated port, or DB schema of its own. The host application registers the four components in dependency order; all collections, services, the CDC consumer, and the generic SearchController are wired into the host's IGNIS container. See ADR-0001.

2. Purpose & Scope

IncludedExcluded
Full-text keyword search over 8 Typesense collectionsOwning the source tables (commerce/pricing/inventory own them)
Optional semantic / hybrid search via auto-embeddingEmbedding model hosting (external Typesense/Google config)
CDC consumer: Debezium → Kafka → Typesense syncThe Debezium connector itself (infra-owned)
Cascade fan-out from join/related tables to principal docsWrite API to mutate documents directly from clients
Ignis-style where/order/fields/include → Typesense translationPattern operators (like/ilike/regexp) — use text search
SearchableControllerMixin for per-entity /search + /search/countTenant scope policy (host overrides resolveSearchScope)
Schema drift detection (manual migration on divergence)Auto-rebuild of diverged collections (manual, avoids data loss)

3. Tech Stack

External:

LibraryPurpose
@venizia/ignisIoC container, BaseComponent, BaseRestController, DI
@venizia/ignis-helpersLogger, applicationEnvironment, HTTP helpers
typesenseTypesense client — collection CRUD, search, import
@platformatic/kafkaCDC Kafka consumer + DLQ producer
avscAvro decoding of Debezium CDC payloads
@hono/zod-openapiZod request/response schemas for search routes
zodSchema validation
lodashUtilities

Internal:

PackagePurpose
@nx/coreCdcTables, ConfigurationRepository, EnvironmentKeys, SystemConfigurations, base classes, DI

4. Project Structure

packages/search/
├── src/
│   ├── index.ts                    # Barrel — re-exports components, services, helpers
│   ├── component.ts                # ApplicationSearchComponent
│   ├── components/
│   │   ├── embedding-configuration.component.ts
│   │   ├── typesense-search-engine.component.ts
│   │   └── cdc.component.ts
│   ├── common/                     # keys, environments, constants, kafka-topics,
│   │                               # search.types, relations, pipeline-config types
│   ├── configurations/             # 8 collection configs + schema-fragments.ts
│   ├── controllers/                # SearchController + searchable.mixin + definitions
│   ├── datasources/                # (re-export)
│   ├── helpers/                    # typesense, converter, registry, include, migration
│   ├── mappers/                    # DB row → Typesense doc (per entity + *-info)
│   ├── services/
│   │   ├── search/                 # SearchService, SearchIndexingService
│   │   ├── cdc/                    # kafka, cdc, cascade, enrichment, circuit-breaker
│   │   └── search-configuration.service.ts
│   ├── migrations/processes/       # backfill processes
│   └── utilities/                  # error-classifier, with-retry, errors
├── scripts/                        # data-feeder, migrate-add-*, check_sync_status.sh
└── package.json

No application.ts / migrate.ts / models/ / repositories of its own — this is a library, not a service.

5. Architecture

@nx/search runs inside the host service (commerce). The diagram shows it embedded.

Detail: see Architecture.

6. Domain Snapshot

No PostgreSQL schema of its own — the "domain" is the set of Typesense collections, each a denormalized projection of source tables.

Full collection schemas + cascade sources: see Domain Model.

7. Surface Summary

REST controllers@nx/search exposes two endpoints; most consumers use the mixin instead of the generic controller. Full schema renders live from the host service's /doc/openapi.json (commerce), not from this library.

SourceBase pathEndpoints
SearchController (generic)/search/{collectionName}2 (GET, GET …/count)
SearchableControllerMixin (per-entity, on consumer controllers)<entity>/search2 per controller
PermissionAction
search:searchSearch documents
search:search-countCount matching documents

Async topics (full reference in API Events):

DirectionCount
Inbound (Kafka CDC)18 topics across 3 schemas
Outbound (Kafka)1 — DLQ (nx.seller.cdc.dlq)
WebSocket out0
BullMQ jobs in/out0

8. Components

Registered by the host in this order:

OrderComponentFilePurpose
1ApplicationSearchComponentsrc/component.tsParses Typesense nodes + the 8 collection configs from env, binds SEARCH_COMPONENT_OPTIONS, registers ConfigurationRepository + SearchConfigurationService
2ApplicationEmbeddingConfigurationComponentsrc/components/embedding-configuration.component.tsLoads optional embedding model config + pipeline config from DB; binds EMBEDDING_MODEL_CONFIG + SEARCH_PIPELINE_CONFIG
3TypesenseSearchEngineComponentsrc/components/typesense-search-engine.component.tsBuilds TypesenseHelper, registers collections into CollectionRegistry (wires embed.from), registers services + SearchController, runs schema-drift check
4ApplicationCdcComponentsrc/components/cdc.component.tsStarts CDCKafkaService on ALL_CDC_TOPICS, with optional DLQ + circuit breaker

9. Services

ServiceFileOne-liner
SearchServicesrc/services/search/search.service.tsQuery-side: Ignis filter → Typesense, resolve include, return { count, data }
SearchIndexingServicesrc/services/search/search-indexing.service.tsWrite-side: upsert/delete single + batch, throughput metrics, getHealth()
CDCServicesrc/services/cdc/cdc.service.tshandleBatch() — routes CDC rows to mappers, upsert/delete
CDCCascadeServicesrc/services/cdc/cdc-cascade.service.tsFans join/related-table changes out to recompute principal docs
CDCEnrichmentServicesrc/services/cdc/cdc-enrichment.service.tsHydrates docs with cross-collection data
CDCCircuitBreakerServicesrc/services/cdc/cdc-circuit-breaker.service.tsProbes Typesense health, pauses consumption when down (opt-in)
CDCKafkaServicesrc/services/cdc/cdc-kafka.service.tsKafka consumer, batching, DLQ routing
SearchConfigurationServicesrc/services/search-configuration.service.tsReads embedding + pipeline config from Configuration table

10. Repositories

RepositoryTableSourceCustom Methods
ConfigurationRepositorycore.Configuration@nx/core— (registered, not owned; reads embedding/pipeline config)

Search owns no tables; it has no repositories of its own.

11. Entry Points

FilePurpose
src/index.tsBarrel export — host imports components from here
src/component.tsApplicationSearchComponent (entry component)
scripts/migrate-add-references.tsBackfill relation/reference fields in Typesense (migrate:references)
scripts/migrate-add-denorm-fields.tsBackfill denormalized fields (migrate:denorm)
scripts/data-feeder/index.tsFeed fake data via Commerce API (feed-data)

No bootstrapApplication() / bootstrapMigration() — those belong to the host service.

12. Configuration

Typesense nodes/API key, CDC + circuit-breaker env, DB-stored embedding + pipeline config: see Configuration.

13. Operations

Runs inside commerce — no independent deployment. Schema migration, CDC lag, sync diagnostics: see Operations.

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.