Implement NotificationRepository with role-scoped queries
epic-in-app-notification-centre-foundation-task-004 — Create the NotificationRepository class backed by Supabase. Implement: getNotifications(userId, {limit, offset, typeFilter}) with role-aware query expansion for coordinators and org-admins, getUnreadCount(userId), markAsRead(notificationId), markAllAsRead(userId), and deleteNotification(notificationId). All queries must respect the RLS policies defined in the migration. Map Supabase rows to typed Notification domain objects via the Notification model's fromJson.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 2 - 518 tasks
Can start after Tier 1 completes
Implementation Notes
Define `INotificationRepository` as an abstract class first — this enables BLoC/Riverpod layers and tests to depend on the interface, not the concrete Supabase implementation. For role-aware query expansion, prefer a Supabase RPC (stored function) over client-side joins to keep the logic server-side and RLS-safe. The coordinator expansion query should accept `userId` and return the union of the user's own notifications plus those of their managed mentors. Map all `PostgrestException` errors in a `_handleError(Object e)` helper that converts to domain exceptions — this keeps all Supabase-specific error codes in one place.
Use `Notification.fromJson` (from task-003) for row mapping. For Riverpod, expose as a `Provider
Testing Requirements
Two test layers: (1) Unit tests using `flutter_test` with a mocked `SupabaseClient` (via `mockito` or `mocktail`) — verify each method calls the correct Supabase table/RPC with the expected arguments and maps responses to domain objects. (2) Integration tests against a local Supabase instance (Docker) — verify RLS policies are respected, role-expansion returns the correct superset for coordinator, pagination returns correct slices, and error paths (not found, forbidden) throw the expected domain exceptions. Target 90%+ branch coverage on the repository class itself.
Supabase Realtime channels on mobile networks can drop silently. If reconnection logic is flawed, users miss notifications without knowing it, undermining the audit-trail guarantee.
Mitigation & Contingency
Mitigation: Implement exponential-backoff reconnection with a maximum of 5 retries; expose a channel-status stream to the BLoC so it can trigger a full-fetch fallback when the channel reconnects after a gap.
Contingency: If Realtime reliability proves insufficient in production, fall back to polling the repository every 60 seconds as a background supplement to the Realtime channel.
Coordinator and org-admin RLS expansions require joining user_roles and org_memberships tables. An incorrect policy could expose notifications to wrong users or block legitimate access entirely.
Mitigation & Contingency
Mitigation: Write dedicated RLS integration tests for each role (peer mentor, coordinator, org admin) using separate Supabase test projects. Review policies with the security checklist before merging.
Contingency: If an RLS defect is discovered post-deployment, disable the expanded-scope policy and revert to user-scoped-only access while a corrected migration is prepared and tested.
JSONB payload structure may vary across notification types created by different Edge Functions (reminder, expiry, scenario, pause). Missing or renamed fields will cause runtime parse failures.
Mitigation & Contingency
Mitigation: Define a canonical NotificationPayload union type in a shared schema document. Each Edge Function must validate its payload against this schema before inserting. Add fallback parsing with default values in the domain model.
Contingency: Wrap all payload parsing in try/catch and log malformed payloads to a monitoring channel; render a generic notification item rather than crashing when the payload cannot be parsed.