Implement in-app pause notification storage and display
epic-peer-mentor-pause-management-core-workflows-task-011 — Extend PauseNotificationService to persist in-app notifications to the notifications table when a pause or reactivation event occurs. Each notification record should include type (pause_activated / mentor_reactivated), mentor name, timestamp, coordinator_id, and deep_link pointing to the CoordinatorPauseRosterScreen. Ensure notifications appear in the existing notification centre with correct role-aware filtering.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 5 - 253 tasks
Can start after Tier 4 completes
Implementation Notes
Implement notification persistence as a fire-and-forget call inside PauseNotificationService using a try/catch that logs failures to the app's error reporting service without rethrowing. Do not use a database transaction that couples notification creation to the pause state update — they should be independent operations. The deep_link should follow the app's existing internal routing convention (e.g., '/coordinator/pause-roster?mentorId=uuid'). For Supabase Realtime badge updates, subscribe to the notifications channel filtered by coordinator_id == auth.uid() AND read_at IS NULL in the notification centre BLoC — increment the unread count on INSERT events and decrement on UPDATE (read_at set).
Use server-side default for created_at (now()) — do not send a client timestamp.
Testing Requirements
Write unit tests for PauseNotificationService covering: (1) correct notification record structure built for pause_activated type, (2) correct structure for mentor_reactivated type, (3) notification insert failure is caught and does not throw or propagate to the caller, (4) deep_link string correctly encodes the mentor ID as a query parameter. Write integration tests verifying: (5) after activatePause() succeeds, a notification row exists in the notifications table with correct coordinator_id, (6) RLS prevents a different coordinator from querying the inserted notification. Test the mark-as-read flow by asserting the read_at column is set after the coordinator navigates via the deep link.
Concurrent status transitions (e.g., coordinator and automated scheduler both attempting to update the same mentor's status simultaneously) may produce race conditions or inconsistent state in the database, leading to audit log gaps or incorrect notifications.
Mitigation & Contingency
Mitigation: Implement all status transitions as atomic Postgres RPC functions with optimistic locking (version column or updated_at check). Use database-level constraints rather than application-level guards as the final enforcement point.
Contingency: Add a compensation job that reconciles status and log table consistency on each nightly scheduler run, surfacing any discrepancies to coordinator dashboards.
The coordinator-to-mentor assignment relationship may not always be 1:1 or may be stale (coordinator reassigned after a pause was set), causing notifications to be sent to the wrong coordinator or not sent at all.
Mitigation & Contingency
Mitigation: Query the assignment relationship at notification dispatch time rather than caching it at pause creation time. Add a fallback to notify the chapter administrator if no active coordinator assignment exists.
Contingency: Log all undeliverable notification attempts with the originating mentor ID so administrators can manually follow up, and surface undelivered notification counts on the coordinator dashboard.
The CoordinatorPauseRosterScreen may load slowly for coordinators managing large rosters with many concurrent certification expiry queries, degrading usability on low-bandwidth mobile connections.
Mitigation & Contingency
Mitigation: Use a single Supabase RPC that joins mentor status, certification expiry, and assignment data in one query rather than N+1 individual calls. Implement pagination with a configurable page size and skeleton loading states.
Contingency: Add an offline cache of the last-fetched roster state using Riverpod with SharedPreferences, ensuring coordinators can at minimum view stale data when connectivity is poor.