critical priority low complexity backend pending backend specialist Tier 0

Acceptance Criteria

An abstract class IContactSearchRepository is defined in lib/features/contact_search/domain/repositories/ with method signatures: Future<List<ContactSearchResult>> searchByName(String query), Future<List<ContactSearchResult>> searchByOrganisation(String query), Future<List<ContactSearchResult>> searchByNotes(String keyword), Future<List<ContactSearchResult>> search(String query) (unified search across all fields)
An abstract class IOfflineSearchRepository is defined extending or mirroring IContactSearchRepository with identical method signatures so implementations are drop-in interchangeable
An abstract class ICacheSyncRepository is defined with method signatures: Future<void> syncContacts(List<Contact> contacts), Future<void> syncNotes(List<Note> notes), Future<DateTime?> getLastSyncTime(), Future<void> clearCache()
All method return types use Future<> (async-safe) and accept nullable parameters where appropriate
A ContactSearchResult data class (or freezed union) is defined with fields: id (String), name (String), organisation (String?), chapterAffiliation (String?), role (String?), matchedField (enum: name | organisation | notes), relevanceScore (double)
All interfaces are exported from a single barrel file lib/features/contact_search/domain/repositories/repositories.dart
The file compiles without errors via flutter analyze

Technical Requirements

frameworks
Flutter
Dart
data models
ContactSearchResult
Contact
Note
security requirements
Repository interfaces must not expose raw SQL or Supabase client objects — enforce abstraction boundary

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Place interfaces in the domain layer following clean architecture conventions: lib/features/contact_search/domain/repositories/. Use abstract class rather than abstract interface (Dart 3) for broader compatibility unless the project targets Dart 3.0+ exclusively. Define ContactSearchResult as an immutable data class — consider using the freezed package if already in the project's pubspec.yaml, otherwise a plain class with const constructor and copyWith is sufficient. The matchedField enum drives relevance sorting in the service layer (name matches rank above organisation matches above notes matches), so include it now even though sorting logic lives in the service.

ICacheSyncRepository is intentionally separate from IOfflineSearchRepository to maintain single-responsibility: one interface for reading (search), one for writing (sync).

Testing Requirements

No runtime tests required for this task (interfaces only). However, write a simple compile-time validation: create a test stub class that implements each interface and verify it satisfies the contract by running flutter analyze.

Optionally add a unit test that creates a mock implementation using Mockito or Mocktail and asserts the mock can be assigned to each interface type, confirming Dart's type system accepts the contract.

Epic Risks (3)
high impact medium prob security

Supabase RLS policies may not correctly scope ilike search results to the authenticated user's organisation and chapter, causing data leakage across organisations or empty result sets for valid queries.

Mitigation & Contingency

Mitigation: Reuse and extend existing RLS query builder patterns from the contact-list-management feature. Write integration tests against a seeded multi-organisation test database to verify cross-org isolation before merging.

Contingency: If RLS scoping is insufficient, add an explicit organisation_id filter in the Dart query builder layer as a defence-in-depth measure while the Supabase policy is corrected.

medium impact medium prob integration

Adding new Drift tables for the contact cache may conflict with existing migrations or schema versions in the contact-list-management feature if both features cache the same contacts table, causing migration failures on user devices.

Mitigation & Contingency

Mitigation: Audit existing Drift schema versions from contact-list-management before writing new migrations. Reuse existing cache tables if the schema already covers required fields; only add missing fields via ALTER or new version.

Contingency: If schema conflict occurs, consolidate into a single shared cache table owned by contact-list-management and expose a DAO interface to the search feature, avoiding duplicated schema ownership.

medium impact medium prob scope

The offline cache may surface significantly stale contact data if sync has not run recently, leading coordinators to act on outdated information (wrong phone numbers, changed assignments).

Mitigation & Contingency

Mitigation: Store and surface the last-sync timestamp prominently in the UI layer. Trigger a background cache refresh on app foreground when connectivity is detected.

Contingency: If staleness becomes a reported UX issue, implement a maximum-age threshold that shows a warning banner when the cache is older than a configurable limit (e.g. 24 hours).