Skip to main content
Welcome. This site supports keyboard navigation and screen readers. Press ? at any time for keyboard shortcuts. Press [ to focus the sidebar, ] to focus the content. High-contrast themes are available via the toolbar.
serard@dev00:~/cv

Full-Text Indices Fed by Projections

A search index is a read-optimised view that happens to be optimised for text matching rather than equality lookup. @frenchexdev/ddd-search reifies the port for full-text search and ships a Meilisearch adapter; the discipline the corpus enforces is that search indices, like read models, are derived from events, never authoritative.


What Search Reifies

A team that lets a search index drift from the event-derived truth eventually finds itself in the corner case where the index says "this customer has an active subscription" and the aggregate says it does not. The reason is always the same — somebody wrote directly to the index, or skipped a re-index after a backfill, or let the eventual-consistency window stretch beyond the user's patience. The corpus enforces that search is a projection target, never a write target from outside the projection.

The contract is four operations. index(doc) upserts a document with its id. reindex(docs) is the bulk variant for replaying many documents at once (typically during the projection rebuild). search(query, opts) is the read path — text query, filters, pagination, ordering. delete(id) removes a document when the underlying entity is deleted.


The Runtime: ddd-search and adapters

Two packages — ddd-search and ddd-search-meilisearch-adapter — both M4/M5 stubs pinned to SearchIndexedFromProjectionsRequirement. Meilisearch is the chosen first substrate — fast cold-start, simple operations, good fit for documents that don't justify the operational weight of Elasticsearch. Additional adapters (Elasticsearch, Postgres FTS) are conceivable; the conformance suite is what the port defines.


The Analyzer: ddd-search-analyzer

Spec-first (spec.ts). Priority Medium. Two info-severity naming invariants: DDD-SEARCH-001 for the Index suffix on index classes, DDD-SEARCH-002 for the Search suffix on the port type.


The Codegen: ddd-search-codegen

Two templates produce a per-index stub and a workspace-wide registry. The deeper move comes when the codegen ties the index schema to the read-model type — the projection updates the read model, the projection updates the search index, both shapes derive from the same event handler signatures, the codegen can emit the index schema from the read-model type without hand-keeping the two in sync.


  • Fed by @Projection — every apply<Event> handler that updates a read model usually also updates the matching index.
  • Read by @QueryHandler instances backing the read side of CQRS.
  • Lives behind the @Port/@Adapter discipline — same conformance suite, multiple substrate adapters.

Back to the series index.

⬇ Download