Search & discovery
Autocomplete Suggestions
This ships in the core. It is implemented in src/pages/api/search/suggest.ts. What follows is the plan it was built from, kept as written — the shipped code may go further than it, or differ in the details.
Autocomplete Suggestions is a core feature that provides real-time search suggestions as customers type. It shows matching products, categories, and recent searches to help customers discover faster.
Shipped so far
In the core: GET /api/search/suggest answers popular searches and a few matching posts, pages, products and categories while someone types — public, cached, rate-limited, ranked by the site search itself (accent/case folding, Greek matches Latin, synonyms), only what a visitor could open. The site’s search box on every theme is an accessible combobox (arrow keys, Enter, Escape, announced and visibly highlighted); the storefront starter’s header suggests products and categories. Popular searches are counted privacy-first: only searches that found something, never staff or crawlers, each visitor once per query per day (in memory only), nothing that looks like an email, web address or number; a search is suggested only after the operator’s minimum number of visitors made it, and a blocklist hides words or phrases. Settings → Reading → Search switches suggestions and popular searches on or off and sets the counts; Insights lists what visitors search for.
Still open: a visitor’s own recent searches (kept in their browser).
The problem
Customers don’t know what to search for; they type partial searches and get no suggestions.
What it does
- Real-time suggestions as user types (debounced, <300ms latency) with product/category/search suggestions
- Prioritize popular searches by frequency with up to 10 suggestions per request
- Keyboard navigation: arrow keys to select, enter to search
- Mobile support: dismiss keyboard on selection
- Admin settings: enable/disable, suggestion limit
- Separate suggestion types: products, categories, searches
What it deliberately does NOT do
Each boundary carries its reason. A boundary without a reason gets crossed by the next person who reads this.
- Does NOT support typo tolerance in suggestions (reason: separate fuzzy-search feature)
- Does NOT rank by user behavior (reason: requires ML)
- Does NOT provide autocomplete for filters/facets (reason: separate feature)
- Does NOT track suggestion clicks (reason: analytics feature)
Data model
New table: search_suggestions_cache (id, prefix, suggestions, updated_at) [performance cache].
API
- GET /api/search/autocomplete?q=shi
- GET /api/search/autocomplete?q=shi&type=products,categories
- GET /api/search/popular-searches
Every route added here must also appear in src/pages/openapi.json.ts — a test
fails the build if it does not.
Admin
Settings (enable/disable, limit); cache stats (hit rate, latency); reset cache button.
The seam — why this is core
Core owns: autocomplete API, suggestion ranking, caching. Frontend owns: keyboard nav, UI rendering, debouncing.
Core owns the interface + honest suggestion engine; search UX is storefront infrastructure, not a per-country obligation or credential.
Dependencies
- Assumes product, category, search query APIs exist
- Assumes caching layer exists
Acceptance checks
Each of these must be able to fail. Before claiming this is done, break the code deliberately and watch each one go red.
- GET /api/search/autocomplete?q=shi returns products starting with ‘shi’
- Suggestions include products, categories, recent searches
- Popular searches ranked higher (by frequency)
- Suggestions returned within 100ms (cached)
- Keyboard nav: arrow keys select, enter submits
- Mobile: selection dismisses keyboard
- Can be disabled via admin setting
- Limit changeable 5-20
- All storage drivers support equally
- Separate sections for products/categories/searches
Risks
Cache staleness: if product renamed, old name remains until cache expires. Bias: popular searches may be typos/spam. Performance: 100k+ products slow without indexing. Privacy: popular searches may leak competitor queries.
Commercial context
| Suggested price | free (core) |
| Rival anchor | Shopify: included (Search & Discovery); Magento: included |
The anchor is what the nearest equivalent charges on Shopify or Magento today. It is context for a pricing decision, not the decision.
Generated from the commerce plan. See docs/COMMERCE-PLAN.md for the full
catalogue and CONTRIBUTING.md for how to work on this repository.