high priority low complexity backend pending backend specialist Tier 2

Acceptance Criteria

FilterCriteria model has an availabilityStatus field of type AvailabilityStatus enum with values active, paused, all
AvailabilityStatus defaults to active in FilterCriteria's unnamed constructor so that paused mentors are excluded by default
MentorFilterService.validate() rejects a null availabilityStatus value with a ValidationException
MentorFilterService.toQueryParameters() returns eq('status','active') for AvailabilityStatus.active, eq('status','paused') for paused, and no status filter clause for all
When availabilityStatus is active and specialisationTags is non-empty, both filter clauses are present in the output
When availabilityStatus is all and specialisationTags is empty, the output contains no filter clauses
Unit test: default FilterCriteria has availabilityStatus == active
Unit test: AvailabilityStatus.active + empty tags → only status clause
Unit test: AvailabilityStatus.active + ['hearing-loss'] → status clause AND tags clause
Unit test: AvailabilityStatus.paused + ['mobility'] → paused status clause AND tags clause
Unit test: AvailabilityStatus.all + ['hearing-loss'] → only tags clause (no status clause)
Unit test: AvailabilityStatus.all + empty tags → empty clause list
The pause feature aligns with the product requirement from the workshop summary: coordinators can pause peer mentors without removing them from the system

Technical Requirements

frameworks
Flutter
flutter_test
apis
Supabase PostgREST query builder (for clause generation contract)
data models
FilterCriteria
AvailabilityStatus (enum)
QueryClause (output model)
performance requirements
Filter clause generation is synchronous and adds zero I/O overhead
security requirements
AvailabilityStatus enum values must be mapped to exact database column values via a const lookup map — no string interpolation from user input
Only the three defined enum values are accepted; any deserialization of unknown values must throw a ValidationException

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Define AvailabilityStatus as a Dart enum with a toDbValue() extension method returning the exact Postgres column string (e.g., 'active', 'paused'). This avoids magic strings in the filter translation layer. Extend FilterCriteria as an immutable class using copyWith and Equatable. Add availabilityStatus as a named parameter with a default of AvailabilityStatus.active.

In MentorFilterService.toQueryParameters(), add availability clause generation as a separate private method _availabilityClause(AvailabilityStatus status) that returns null for the all case and a typed clause object for the other two. This keeps each dimension of filtering independently testable. The 'paused' functionality directly supports the HLF and NHF workshop requirement where peer mentors can self-pause without deregistering.

Testing Requirements

Pure unit tests in flutter_test — no widget or async infrastructure needed. Write a parameterised test table covering all six combinations of AvailabilityStatus × {empty tags, non-empty tags}. Additionally test the default constructor produces active status.

Test validate() with a null status field. Test that the enum serialises to and from the database string value correctly (e.g., 'active' ↔ AvailabilityStatus.active). Target 100% line and branch coverage on the availability filter logic.

Component
Mentor Filter Service
service low
Epic Risks (2)
medium impact medium prob technical

The dual BLoC state machines (map view state + filter state) may introduce subtle synchronisation bugs where filter changes do not correctly re-trigger viewport queries, causing stale data to appear on the map.

Mitigation & Contingency

Mitigation: Define all BLoC state transitions in a state diagram before implementation. Use flutter_bloc's BlocObserver in development mode to log every state transition. Write explicit unit tests for filter-change → re-query transitions.

Contingency: If state synchronisation bugs appear in integration testing, refactor to a single unified BLoC that owns both map viewport state and filter state, eliminating cross-BLoC dependencies.

low impact medium prob scope

Cached mentor location data may become stale (mentors move, pause, or revoke consent) and coordinators in offline mode could be shown incorrect mentor information, leading to wasted outreach.

Mitigation & Contingency

Mitigation: Display a clear timestamp on cached data indicating when it was last synced. Set cache TTL to 24 hours and show an 'offline — data from [date]' banner. Revoked consent removes the mentor from the cache on next successful sync via contact-cache-sync-repository.

Contingency: If cache staleness causes user complaints, reduce TTL to 4 hours and implement background sync on app foreground. Accept that very-recently-revoked mentors may appear briefly in offline mode — document this as a known limitation in the privacy policy.