Build validated ILIKE search predicate constructor
epic-contact-list-management-foundation-task-003 — Add the search predicate construction method to ContactRLSQueryBuilder that generates ILIKE patterns for the name and notes columns. Validate the input string (trim, escape special characters, enforce minimum length) before constructing the predicate to prevent accidental full-table scans or injection-style patterns.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 2 - 518 tasks
Can start after Tier 1 completes
Implementation Notes
Implement the escaping logic as a private static method _escapeIlikePattern(String input) that handles %, _, and \ in a single pass using String.replaceAllMapped() or a regex. The minimum length check should be applied AFTER trimming and BEFORE escaping so the length count reflects actual content. For the Supabase .or() call, check the current version of the supabase_flutter package for the correct syntax — the API changed between v1 and v2 (v2 uses .or('name.ilike.%x%,notes.ilike.%x%') as a string filter). Pin to the project's existing supabase_flutter version.
Add a brief inline comment explaining why the minimum length guard exists (performance, not security) to help future maintainers understand the intent.
Testing Requirements
Unit tests (consolidated in task-004) must cover: (1) normal input 'hansen' → pattern '%hansen%' on both columns; (2) input with % character → escaped to '\%'; (3) input with _ character → escaped to '\_'; (4) whitespace-only input → no search predicate appended; (5) single character input → no predicate appended; (6) exactly 2 character input → predicate appended; (7) input over 100 characters → truncated to 100 before pattern construction; (8) combined builder call (forOrganisation + withRole + withSearch) → all three predicates present in correct order. Use flutter_test with mock Supabase builder.
Existing Supabase RLS policies for the contacts and peer_mentors tables may not align with the application-level UserRole model, causing ContactRLSQueryBuilder to construct filter expressions that are redundant, conflicting, or that allow over-fetching. In a multi-chapter context (NHF), this could expose contacts belonging to other chapters.
Mitigation & Contingency
Mitigation: Audit and document the existing RLS policies against the UserRole enum before writing a single line of query builder code. Write integration tests asserting cross-organization data isolation using separate test user tokens for each role.
Contingency: If RLS policies are misaligned at runtime, add an explicit application-level organization_id equality check in ContactRepository as a secondary guard while the database policies are corrected in a coordinated migration.
The Supabase schema for contacts and peer_mentors tables may differ from the expected typed models — missing columns, renamed fields, or type mismatches — causing deserialization failures that surface only at runtime during integration testing.
Mitigation & Contingency
Mitigation: Document expected schema fields upfront and validate against the live Supabase schema at sprint start. Use freezed and json_serializable for compile-time-safe deserialization with explicit required/optional field declarations.
Contingency: Introduce nullable fields with safe defaults for any schema mismatches discovered in testing; log deserialization errors to the monitoring service so schema drift is caught before production deployment.