Storefront and Staff Search on Meilisearch In Progress
Replaced leading-wildcard SQL search with a Meilisearch layer that ranks curated keywords across 13,174 product groups and serves storefront search, autocomplete, and six staff dashboard searches, under 198 passing tests.
Private employer Details are sanitized; architecture and outcomes are described without proprietary identifiers.
At a glance
- product groups with curated keywords and ranks
- 13,174
- passing tests across 35 files
- 198
- entity types rebuilt atomically
- 4
- Role
- Lead Full Stack Developer
- Year
- 2026
- Category
- Full Stack Software Dev
About This Project
Owned the search layer of the v3 platform, built alongside the order pipeline rebuild. A Meilisearch layer replaced leading-wildcard SQL scans for four entity types with atomic staging rebuilds, incremental hooks from every sync and dashboard edit, and hash-based drift checks. It serves public storefront search, suggestions, and header autocomplete with staff-managed synonyms, and ranks the six staff dashboard searches without changing their response shape. Relevance comes from a Postgres-only curation table: a rules pass plus a Claude pass wrote keywords and a three-band rank for all 13,174 enabled product groups, so a product lists before its own lids, straws, and parts, and hand edits are never overwritten by imports.
Technologies Used
Engineering Challenges
01
Search Relevance Without Term Weighting
Meilisearch has no term weighting, so no keyword list could move a lid below the bottle it fits; the engine's word-position tiebreak favoured the short accessory titles. Fixed it with a document-level searchRank from a Postgres-only curation table and a custom ranking rule placed after the text-matching rules and before attribute, measured on the dev index until bottles led for "water bottle" and lids still led for "lid". Synced keywords stay untouched, curated rows replace them per product, and hand edits are never overwritten by imports.
02
Legacy Response Shapes
The six staff searches had screens built around their SQL response shapes. The engine answers which records match, then the rows are re-read from Postgres in rank order, so no dashboard screen changed, the old SQL search stays as a configuration fallback, and a real engine outage answers 503 search_unavailable instead of wrong results.
03
Freshness Without Downtime
Catalog, customer, and category syncs and dashboard edits all change searchable data. Every rebuild lands in a timestamped staging index and swaps in atomically, non-blocking upserts ride on top, and a sampling drift check compares stored document hashes against the live index, so a failed rebuild never serves a half-filled index.
Technical Highlights
Tested Search Layer: 198 search tests across 35 files cover mappers, reindexing, drift, synonyms, suggestions, curated terms, the dashboard search engine, and a live storefront relevance suite that pins product-before-accessory ordering.
Dashboard Search Cutover: The six staff searches (customers, users, categories, product groups, variants, and SKUs) ask Meilisearch which records match, then re-read the rows from Postgres in rank order, so every response keeps its legacy shape. User search re-applies the caller's permission scope on hydration so a stale index document never exposes a user the caller may not see.
Atomic Reindex: Every entity rebuilds into a timestamped staging index with its own settings, loads in 500-row batches, then swaps into the live name. Synonyms live in a Postgres table and are re-applied before every swap.
Curated Search Terms: A Postgres-only table holds curated keywords and a three-band searchRank per product group and is never synced back to the ERP. A rules pass cleans the legacy keyword list and seeds ranks from part and sample-set tags, a Claude pass (in-session subagents over 66 chunks of 200 products, with a Message Batches path for API-key runs) wrote keywords and ranks for all 13,174 enabled groups at a median of 10 keywords each, and a transactional import skips hand-edited rows unless told to overwrite. New products get a rules row on their first catalog sync, and staff edit terms per product in the dashboard with the group reindexing on save.
Storefront Search: Public search and suggest routes carry rate limits and query telemetry, and in-stock and clearance facets are derived at index time; on the 53,327-document dev index the facet counts matched Postgres exactly.
Business Logic
Search Performance and Control: One engine replaces the leading-wildcard LIKE scans behind staff and storefront search, adds typo-tolerant autocomplete, and lets merchandisers curate results through synonyms, per-product keywords and ranks, and per-variant hiding without deleting data, so a search for a product lists the product before its lids, straws, and parts.
One Engine, Two Audiences: Shoppers and staff search the same indexes, so a relevance fix for the storefront reaches the dashboard the same day, and the old SQL path stays one configuration flag away during cutover.
ERP Boundary: Curated search data lives only in Postgres and never flows back into the ERP, so merchandising can tune results without touching the system of record.