# Search UX — Steps status **All 14 steps: DONE (100%)** ✅ ## Done - [x] Step 1: Audit current codebase for existing search and provider logic on frontend and server - [x] Step 2: Design and scaffold Provider Registry on frontend and server - [x] Step 3: Implement SearchService with multi-provider params and HTTP request - [x] Step 4: Build SearchBoxComponent with chips, @autocomplete, and keyboard shortcuts - [x] Step 5: Build ProviderPickerComponent (Ctrl/⌘+K modal) with filtering, History column and apply - [x] Step 6: Build SearchSuggestionsComponent with grouped sections, per-provider unsupported rows and deep-links - [x] Step 7: Add router query-param sync and default provider preference loading (Search page fallback to user preference) - [x] Step 8: Implement backend /api/search with providers param and fan-out to server/providers handlers - [x] Step 9: Persist default providers preference in user profile (client + server endpoints wired, tested) - [x] Step 10: Add keyboard accessibility and a11y behaviors (Tab/Shift+Tab focus trap, Esc, aria, focus restore) - [x] Step 11: Write unit tests (SearchService, ProviderPicker toggle, @ parsing) - [x] Step 12: Write basic e2e scenarios for providers filtering and deep-link - [x] Step 13: Add minimal telemetry hooks and events - [x] Step 14: Update README with search UX section, keyboard shortcuts and usage notes ## Test commands ```bash npm run test:search # Step 11 — unit tests: SearchService + @ parsing + ProviderPicker npm run test:search-e2e # Step 12 — e2e scenarios against a real isolated server npm run test:preferences # Step 9 — defaultProviders persistence npm run test:telemetry # Step 13 — telemetry events (insert/list/count) ``` ## Implementation notes - **Step 11** (`src/app/search/search.service.spec.ts`, `search-components.spec.ts`): ts-node runs with isolated transpilation (no decorator output => no ɵfac), so TestBed cannot instantiate Angular classes. Instead the specs import `@angular/compiler`, then build components inside `Injector.create(...)` + `runInInjectionContext(...)` with fakes for SearchService/UserService/HistoryService/TelemetryService and mock internal schedulers (ɵChangeDetectionScheduler, ɵEffectScheduler with immediate-run effects). - **Step 12** (`server/tests/search.e2e.test.mjs`): spawns a real server (temp SQLite DB via NEWTUBE_DB_FILE, ephemeral port, test JWT secret) and asserts: providers filter targets exactly the requested ids; deep-link single-provider; invalid providers fall back to the full registry; defaultProviders preference persists; SPA /search route serves the shell. Assertions are on fan-out shape, not on external provider content. - **Step 13**: `telemetry_events` table (db/migrations/20250924_add_telemetry_events.sql), server helpers (insertTelemetryEvent/listTelemetryEvents/countTelemetryEvents) + routes `POST /telemetry/events` (whitelisted event names, rate-limited), `GET /telemetry/events|/summary` (own-events only). Front: `TelemetryService` (fire-and-forget, dedup 500ms window, payload sanitization) wired into SearchBox hooks: search_submit, provider_picker_open, provider_apply, at_autocomplete_use, quick_menu_open. - **Step 14**: README gained a "Recherche unifiée" section (chips, @autocomplete, Ctrl/⌘+K picker, deep-links, preference fallback, a11y), API endpoints, test commands and roadmap updates. GIF placeholder TODO added. - CI (`.github/workflows/ci.yml`) now runs preferences, telemetry, search unit and e2e tests.