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
| Property | Value |
|---|---|
| Package | @nx/search |
| Code | LIB-SEARCH |
| Type | Library / component package (consumed by commerce) |
| Runtime | Bun (>=1.3.8) — runs inside the host process |
| Base Class | N/A — no Application class; exports BaseComponent subclasses |
| Location | packages/search |
| Base Path | /search (mounted under the host service's base path) |
| Dev Port | N/A — library package, no port of its own |
| Container Port | N/A — runs in the host container (commerce) |
| Snowflake ID | N/A — host service owns ID allocation |
| Search Engine | Typesense ^3.0.3 (nodes as protocol:host:port) |
| Sync Source | Debezium → Kafka CDC (public, pricing, inventory schemas) |
| Consumed by | commerce |
| 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 genericSearchControllerare wired into the host's IGNIS container. See ADR-0001.
2. Purpose & Scope
| Included | Excluded |
|---|---|
| Full-text keyword search over 8 Typesense collections | Owning the source tables (commerce/pricing/inventory own them) |
| Optional semantic / hybrid search via auto-embedding | Embedding model hosting (external Typesense/Google config) |
| CDC consumer: Debezium → Kafka → Typesense sync | The Debezium connector itself (infra-owned) |
| Cascade fan-out from join/related tables to principal docs | Write API to mutate documents directly from clients |
Ignis-style where/order/fields/include → Typesense translation | Pattern operators (like/ilike/regexp) — use text search |
SearchableControllerMixin for per-entity /search + /search/count | Tenant 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:
| Library | Purpose |
|---|---|
@venizia/ignis | IoC container, BaseComponent, BaseRestController, DI |
@venizia/ignis-helpers | Logger, applicationEnvironment, HTTP helpers |
typesense | Typesense client — collection CRUD, search, import |
@platformatic/kafka | CDC Kafka consumer + DLQ producer |
avsc | Avro decoding of Debezium CDC payloads |
@hono/zod-openapi | Zod request/response schemas for search routes |
zod | Schema validation |
lodash | Utilities |
Internal:
| Package | Purpose |
|---|---|
@nx/core | CdcTables, 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.jsonNo
application.ts/migrate.ts/models//repositoriesof 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.
| Source | Base path | Endpoints |
|---|---|---|
SearchController (generic) | /search/{collectionName} | 2 (GET, GET …/count) |
SearchableControllerMixin (per-entity, on consumer controllers) | <entity>/search | 2 per controller |
| Permission | Action |
|---|---|
search:search | Search documents |
search:search-count | Count matching documents |
Async topics (full reference in API Events):
| Direction | Count |
|---|---|
| Inbound (Kafka CDC) | 18 topics across 3 schemas |
| Outbound (Kafka) | 1 — DLQ (nx.seller.cdc.dlq) |
| WebSocket out | 0 |
| BullMQ jobs in/out | 0 |
8. Components
Registered by the host in this order:
| Order | Component | File | Purpose |
|---|---|---|---|
| 1 | ApplicationSearchComponent | src/component.ts | Parses Typesense nodes + the 8 collection configs from env, binds SEARCH_COMPONENT_OPTIONS, registers ConfigurationRepository + SearchConfigurationService |
| 2 | ApplicationEmbeddingConfigurationComponent | src/components/embedding-configuration.component.ts | Loads optional embedding model config + pipeline config from DB; binds EMBEDDING_MODEL_CONFIG + SEARCH_PIPELINE_CONFIG |
| 3 | TypesenseSearchEngineComponent | src/components/typesense-search-engine.component.ts | Builds TypesenseHelper, registers collections into CollectionRegistry (wires embed.from), registers services + SearchController, runs schema-drift check |
| 4 | ApplicationCdcComponent | src/components/cdc.component.ts | Starts CDCKafkaService on ALL_CDC_TOPICS, with optional DLQ + circuit breaker |
9. Services
| Service | File | One-liner |
|---|---|---|
SearchService | src/services/search/search.service.ts | Query-side: Ignis filter → Typesense, resolve include, return { count, data } |
SearchIndexingService | src/services/search/search-indexing.service.ts | Write-side: upsert/delete single + batch, throughput metrics, getHealth() |
CDCService | src/services/cdc/cdc.service.ts | handleBatch() — routes CDC rows to mappers, upsert/delete |
CDCCascadeService | src/services/cdc/cdc-cascade.service.ts | Fans join/related-table changes out to recompute principal docs |
CDCEnrichmentService | src/services/cdc/cdc-enrichment.service.ts | Hydrates docs with cross-collection data |
CDCCircuitBreakerService | src/services/cdc/cdc-circuit-breaker.service.ts | Probes Typesense health, pauses consumption when down (opt-in) |
CDCKafkaService | src/services/cdc/cdc-kafka.service.ts | Kafka consumer, batching, DLQ routing |
SearchConfigurationService | src/services/search-configuration.service.ts | Reads embedding + pipeline config from Configuration table |
10. Repositories
| Repository | Table | Source | Custom Methods |
|---|---|---|---|
ConfigurationRepository | core.Configuration | @nx/core | — (registered, not owned; reads embedding/pipeline config) |
Search owns no tables; it has no repositories of its own.
11. Entry Points
| File | Purpose |
|---|---|
src/index.ts | Barrel export — host imports components from here |
src/component.ts | ApplicationSearchComponent (entry component) |
scripts/migrate-add-references.ts | Backfill relation/reference fields in Typesense (migrate:references) |
scripts/migrate-add-denorm-fields.ts | Backfill denormalized fields (migrate:denorm) |
scripts/data-feeder/index.ts | Feed 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.
14. Related Pages
- Architecture
- Domain Model
- API Events
- Integration
- Configuration
- Operations
- Semantic Search Selection — vector DB + embedding model evaluation
- Decisions
- REST endpoints — live OpenAPI at the host service
/v1/api/commerce/doc/openapi.json - Commerce — host / primary consumer