- Add canonicalJson() helper to sort object keys recursively
- Add generateIdempotencyKey() to create per-query idempotency keys
from index + canonicalized request body (hash-based)
- Send Idempotency-Key header on search requests for server-side coalescing
- Add unit test (test_idempotency_key.js) verifying:
- Same parameters produce same key
- Different parameters produce different keys
- Key format is correct (search-{hex})
- Canonical JSON ensures consistency across key orderings
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Implement iframe mode (?embed=true) that strips chrome and sends postMessage events for height auto-resize and result-clicked
- Implement headless mode (?headless=true) that returns only results container without search input or facets
- Add web component widget (/ui/widget.js) that registers <miroir-search> custom element with index and accent attributes
- Add custom template support (result_template: custom) with Handlebars-style interpolation ({{field}}, {{#if}}...{{/if}})
- Templates stored in search_ui_config table via task_store, with validation and error handling
- UI falls back to default card template on custom template errors
- Add GET /_miroir/ui/search/{index}/config endpoint to retrieve stored configuration
Closes: miroir-uhj.21.5
Implemented comprehensive SPA capabilities for the end-user search UI:
- **Instant-search**: 150ms debounce with §13.10 query coalescing
- **URL state encoding**: q+filters+sort+page in URL for bookmarkable searches
- **Keyboard navigation**: / to focus, ↑↓ to navigate results, Enter to open, Esc to clear
- **Highlighting**: Uses Meilisearch _formatted output for matched terms
- **Sort options**: Configurable sort dropdown with per-page selector (12/24/48)
- **Typo tolerance UI**: "Did you mean" suggestions on zero hits
- **Analytics beacon**: Click-through and latency tracking via POST /_miroir/ui/search/{index}/beacon
- **Dark mode**: Manual toggle + prefers-color-scheme support, stored in localStorage
- **Responsive design**: Mobile bottom-sheet facets, tablet 2-col, desktop 3-col, max-width 1440
- **Accessibility**: WCAG 2.2 AA - ARIA labels, live regions, keyboard shortcuts, screen reader support
- **Skeleton loaders**: Layout-shift-free loading states during instant-search keystrokes
- **Empty state**: Popular query suggestions (configurable via §13.18 canaries)
Design philosophy: Content-first with generous whitespace, system fonts, subtle motion
(180ms fade + translate), rounded corners (12px), soft shadows. Single configurable
accent color drives CTAs and highlights.
Bundle size: ~24KB total (HTML: 4KB, CSS: 11KB, JS: 20KB) - well under 60KB target.
Closes: miroir-uhj.21.4
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>