critical priority medium complexity backend pending backend specialist Tier 2

Acceptance Criteria

PeerMentorStatusRepository exposes a Future<PeerMentorStatus> getCurrentStatus(String peerMentorId) method that reads from the peer_mentor_status table via Supabase client and returns a typed model.
Repository exposes Future<PeerMentorStatus> activatePause({required String peerMentorId, required String reason, DateTime? expectedReturnDate}) that calls the activate_pause RPC and returns the updated status.
Repository exposes Future<PeerMentorStatus> deactivatePause(String peerMentorId) that calls the deactivate_pause RPC.
Repository exposes Stream<PeerMentorStatus> watchStatus(String peerMentorId) that subscribes to Supabase Realtime on the peer_mentor_status table filtered by id=peerMentorId and emits typed events on each change.
Repository exposes Future<List<PeerMentorStatusLogEntry>> getStatusHistory(String peerMentorId) that queries peer_mentor_status_log ordered by created_at DESC.
All methods propagate typed exceptions (PeerMentorStatusException) on Supabase errors rather than raw PostgrestException.
Riverpod providers (peerMentorStatusRepositoryProvider, currentPeerMentorStatusProvider(id), peerMentorStatusStreamProvider(id)) are defined and exported.
Repository is fully unit-testable via a mockable SupabaseClient abstraction — no static Supabase.instance references inside the class.
Realtime subscription is cancelled when the stream subscription is cancelled (no resource leaks).
All public methods have Dart doc comments explaining parameters, return values, and thrown exceptions.

Technical Requirements

frameworks
Flutter
Riverpod
Supabase Dart SDK
Supabase Realtime
apis
activate_pause RPC
deactivate_pause RPC
get_active_pauses_for_chapter RPC
peer_mentor_status table (SELECT via RLS)
peer_mentor_status_log table (SELECT via RLS)
data models
assignment
certification
performance requirements
getCurrentStatus must complete within 300ms on a stable mobile connection.
Realtime stream must reconnect automatically on connection drop using Supabase Realtime's built-in retry — no custom reconnect loop needed.
Status history query must be paginated (default limit 50) to avoid loading unbounded log entries.
security requirements
Supabase client must be initialized with the authenticated user's session — never with the service role key.
RPC calls must not include organization_id as a parameter from the client; it must be derived server-side from the JWT.
Typed exceptions must not expose raw Postgres error messages to the UI layer — log internally, surface a user-safe message.

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Use a constructor-injected SupabaseClient (not Supabase.instance) to keep the class unit-testable. Define PeerMentorStatus and PeerMentorStatusLogEntry as immutable Dart classes with fromJson factories — use freezed if the codebase already uses it for consistency. For the Realtime subscription, use supabase.channel('peer_mentor_status:$peerMentorId').onPostgresChanges(...).subscribe() and store the channel reference so it can be removed on stream cancellation. Wrap all async Supabase calls in try/catch on PostgrestException and rethrow as PeerMentorStatusException with a code enum (notFound, unauthorized, serverError) so the BLoC layer can pattern-match without importing Supabase types.

Register providers using Riverpod's autoDispose modifier for stream providers to ensure subscriptions are cleaned up when the widget tree disposes the provider. Keep the repository focused on data access — no business logic (e.g., 'should I allow pause?') belongs here.

Testing Requirements

Write unit tests using flutter_test and mocktail (or mockito) to cover: (1) getCurrentStatus returns correct typed model on success, (2) getCurrentStatus throws PeerMentorStatusException on PostgrestException, (3) activatePause calls the correct RPC with correct parameters, (4) deactivatePause calls the correct RPC, (5) watchStatus emits updated model on Realtime event, (6) watchStatus stream cancellation triggers unsubscribe on Supabase channel, (7) getStatusHistory returns list ordered by created_at DESC, (8) getStatusHistory respects pagination limit. Integration tests against a Supabase test project should verify the full round-trip: activate → realtime event received → deactivate → history contains both entries. Aim for 90%+ line coverage on the repository class.

Component
Peer Mentor Status Repository
data medium
Epic Risks (3)
high impact medium prob security

Supabase RLS policies for coordinator-scoped status queries may be difficult to express correctly, especially for peer mentors assigned to multiple coordinators or chapters, leading to data leakage or overly restrictive access blocking valid queries.

Mitigation & Contingency

Mitigation: Design RLS policies using security-definer RPCs rather than table-level policies for complex multi-coordinator scenarios. Write a comprehensive RLS test matrix covering all role and assignment permutations before marking complete.

Contingency: Fall back to application-level filtering in the repository layer with explicit coordinator_id parameter checks if RLS proves intractable, and document the trade-off for security review.

high impact medium prob dependency

The HLF Dynamics portal API contract may be undocumented or subject to change, causing the DynamicsPortalClient to break during development or production rollout.

Mitigation & Contingency

Mitigation: Obtain the full Dynamics portal API specification and credentials early in the sprint. Build the client behind a well-defined interface so the HLF-specific implementation can be swapped without affecting upstream services.

Contingency: If the Dynamics API is unavailable or unstable, stub the client with a feature-flag-guarded no-op implementation so all other epics can proceed to completion independently.

medium impact low prob technical

Supabase Edge Functions used as the nightly scheduler host may have cold-start latency or execution time limits that prevent reliable nightly certification checks on large mentor rosters.

Mitigation & Contingency

Mitigation: Benchmark Edge Function execution time against the expected roster size. Design the expiry check to process in paginated batches to stay within execution limits. Use pg_cron with a direct database function as an alternative trigger if Edge Functions prove unreliable.

Contingency: Migrate the scheduler trigger to pg_cron invoking a Postgres function directly, removing the Edge Function dependency entirely for the scheduling layer.