From 76e21b08fff2fa016d8b2be138730cf9cab88ada Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Tue, 19 May 2026 12:49:52 -0400 Subject: [PATCH] fix(idaa): remove over-filtering of API text search results in recovery meetings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The secondary client-side filter was re-checking qry_str against name, description, location_text, and default_qry_str on the API response. This silently dropped meetings that the API correctly matched via default_qry_str (a backend-generated combined index containing contact name/email) — because that field is not always present in the response body. The API's LIKE search on default_qry_str is already exact. The secondary filter should only correct structured dimensions (type, physical/virtual OR-logic) where the backend uses AND logic that the frontend must compensate for. Text search is left to the API. Root cause confirmed: STORED GENERATED columns in the event table needed a rebuild; frontend filtering was masking results that the API returned correctly. Co-Authored-By: Claude Sonnet 4.6 --- .../(idaa)/recovery_meetings/+page.svelte | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/routes/idaa/(idaa)/recovery_meetings/+page.svelte b/src/routes/idaa/(idaa)/recovery_meetings/+page.svelte index 9f727171..e07365c5 100644 --- a/src/routes/idaa/(idaa)/recovery_meetings/+page.svelte +++ b/src/routes/idaa/(idaa)/recovery_meetings/+page.svelte @@ -301,8 +301,16 @@ async function handle_search_refresh(qry_key: string) { if (current_search_id === last_search_id) { let api_results = results || []; - // SECONDARY FILTER: Ensure API results respect exact UI filters (handles backend broadness) - api_results = api_results.filter((ev: any) => { + // SECONDARY FILTER: Re-apply structured filters the API may handle loosely. + // WHY type/physical/virtual: the backend uses AND logic for body filters, so + // physical+virtual together would incorrectly exclude either-only meetings — + // we pass only one at a time and handle OR logic here. + // WHY NOT qry_str: the API already applied exact LIKE search on default_qry_str + // (a backend-generated combined index that includes contact name/email). Re-running + // text filtering client-side against the response fields silently drops meetings + // that matched only via default_qry_str (e.g., by contact name) because that + // field may not be present in the response body or may not duplicate the match. + api_results = api_results.filter((ev) => { if (qry_type && ev.type !== qry_type) return false; if (qry_physical || qry_virtual) { let match = false; @@ -310,19 +318,6 @@ async function handle_search_refresh(qry_key: string) { if (qry_virtual && ev.virtual == true) match = true; if (!match) return false; } - if (qry_str && qry_str.length >= 3) { - const name = (ev.name ?? '').toLowerCase(); - const desc = (ev.description ?? '').toLowerCase(); - const loc = (ev.location_text ?? '').toLowerCase(); - const dqs = (ev.default_qry_str ?? '').toLowerCase(); - if ( - !name.includes(qry_str) && - !desc.includes(qry_str) && - !loc.includes(qry_str) && - !dqs.includes(qry_str) - ) - return false; - } return true; });