Build Supabase query predicates for each role scope
epic-in-app-notification-centre-services-task-002 — Implement the Supabase query predicate builders inside the Role-Aware Notification Filter Service for each role scope: peer_mentor (own notifications only), coordinator (own + assigned peer mentor notifications), and org_admin (all notifications within the organisation). Predicates must produce valid PostgREST filter strings consumable by the notification repository query layer.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 1 - 540 tasks
Can start after Tier 0 completes
Implementation Notes
Model each predicate builder as a static method or top-level function: `buildPeerMentorPredicate(String userId, String orgId)`, `buildCoordinatorPredicate(String userId, List
Be mindful that PostgREST `in.(...)` clauses have a practical limit around 100 values; document this and add a guard that logs a warning if exceeded.
Testing Requirements
Unit tests (flutter_test) for each of the three predicate builder functions covering: (1) happy path with realistic user context, (2) coordinator with zero assigned mentors, (3) coordinator with maximum expected mentors (50), (4) org_admin with large org, (5) unknown role throws ArgumentError. Integration test verifying the generated predicate string is accepted by a local Supabase test instance or supabase_flutter mock without syntax errors. Test that org_id scoping is always present in the output regardless of role. 90%+ branch coverage on the predicate builder module.
A Realtime INSERT event arriving during an in-flight mark-all-read operation can cause the new notification to be incorrectly marked read in the optimistic state update, silently hiding it from the user.
Mitigation & Contingency
Mitigation: Process Realtime events sequentially in the BLoC event queue using bloc_concurrency's sequential transformer. The mark-all-read event should only affect notifications whose IDs were fetched before the operation started.
Contingency: Add a reconciliation step after mark-all-read that re-fetches the unread count from the repository and corrects the BLoC state if it diverges from the server value.
A coordinator assigned to many peer mentors may trigger a query returning hundreds or thousands of notifications. Without pagination and query optimisation, the initial load will be slow and memory-heavy.
Mitigation & Contingency
Mitigation: Enforce server-side pagination (50 items per page) in the Role-Aware Filter's query predicates. Add a composite index on (org_id, user_id, created_at DESC) and profile query plans before shipping.
Contingency: If query performance is insufficient for large coordinator scopes, introduce a server-side RPC function that pre-aggregates visible notification IDs and returns only the first page, deferring full scope resolution to lazy-load.
If the read-state optimistic update rolls back frequently due to intermittent connectivity, users will observe notifications toggling between read and unread, creating confusion and distrust of the feature.
Mitigation & Contingency
Mitigation: Queue failed mutations in a local retry store and re-attempt on next connectivity event using a connectivity-aware retry service. Show a non-intrusive banner if offline rather than applying optimistic updates.
Contingency: Disable optimistic updates for mark-as-read in low-connectivity scenarios detected by the connectivity provider, instead showing a loading indicator until server confirmation.