critical priority low complexity backend pending backend specialist Tier 1

Acceptance Criteria

PeerMentorRepository class exists under lib/features/peer_mentor/data/repositories/ and is registered as a Riverpod provider
fetchPeerMentorProfile(String mentorId) is an async method returning Future<PeerMentorProfile>
Method queries the peer_mentors table using Supabase .from('peer_mentors').select().eq('id', mentorId).single()
Successful response is mapped to PeerMentorProfile via PeerMentorProfile.fromJson()
When Supabase returns no matching row (PostgrestException with code PGRST116), the method throws a typed MentorNotFoundException(mentorId) rather than propagating the raw Supabase exception
Network and unexpected Supabase errors are wrapped in a typed RepositoryException and rethrown — no raw exceptions escape the repository boundary
Method does NOT apply any additional client-side filtering by organization_id or role — RLS at Supabase handles access control
Repository is injected with the Supabase client via Riverpod provider (supabaseClientProvider or equivalent), not instantiated directly
Unit test with mocked Supabase client passes for: success case, not-found case, and generic network error case

Technical Requirements

frameworks
Flutter
Riverpod
Dart
apis
Supabase PostgREST — peer_mentors table SELECT by id
data models
PeerMentorProfile
performance requirements
Single SELECT query — do not fetch related tables in this method; keep profile fetch atomic and fast
Method must complete within 3 seconds on a standard mobile connection or surface a timeout error
security requirements
Never bypass Supabase RLS by using the service_role key in client-side code
Do not log raw API responses that may contain PII — log only error codes and mentorId for debugging
mentorId parameter must be validated as non-empty before calling Supabase to avoid broad table scans

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Check whether the project already has a base Repository class or interface — if so, extend it. Define a PeerMentorRepositoryProvider using Riverpod's riverpod_annotation or plain Provider/StateNotifierProvider as the project convention dictates. The repository should expose an abstract interface (IPeerMentorRepository) to allow easy mocking in BLoC tests. Catch PostgrestException specifically before catching the base Exception to ensure correct error classification.

The PGRST116 code indicates 'JSON object requested, multiple (or no) rows returned' from PostgREST — this is the standard not-found signal when using .single(). Avoid using .maybeSingle() unless a null return is semantically valid for this use case (a missing profile should be an error state, not a null state).

Testing Requirements

Unit tests using flutter_test with a mocked SupabaseClient (use mockito or mocktail, whichever the project already uses). Test file: test/features/peer_mentor/data/repositories/peer_mentor_repository_test.dart. Required test cases: (1) returns PeerMentorProfile when Supabase returns valid JSON, (2) throws MentorNotFoundException when Supabase returns PGRST116 error code, (3) throws RepositoryException for unexpected PostgrestException, (4) throws ArgumentError or RepositoryException when mentorId is empty string. Mock the Supabase .from().select().eq().single() call chain.

Do not make real network calls in tests.

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

Supabase RLS policies for peer mentor data may block coordinator queries if the RLS rules are written for peer-mentor-self access only, requiring policy updates that affect other features sharing the same tables.

Mitigation & Contingency

Mitigation: Review existing RLS policies on peer_mentors, certification_records, and activity_log tables before writing repository queries. Coordinate with the database team to add coordinator-role predicates without weakening existing mentor-self policies.

Contingency: If policy changes are blocked, implement a Supabase Edge Function as a secure query proxy that enforces authorization server-side, avoiding direct RLS policy modification.

medium impact medium prob technical

The activity log table schema may not have a mentor_id foreign key column or may require a JOIN through an intermediate table, making the aggregation query significantly more complex than anticipated.

Mitigation & Contingency

Mitigation: Inspect the actual Supabase activity_log table schema before starting the MentorActivityLogRepository implementation. Document the exact JOIN path needed and validate it returns correct results for a known mentor.

Contingency: If schema requires complex multi-table aggregation, implement a Supabase database function (RPC) and expose it via the repository's fetchSummary method to keep Dart code clean.

high impact low prob dependency

The Blindeforbundet assignment table may not yet exist in the shared Supabase schema or may have a different structure than assumed, blocking the AssignmentHistoryRepository implementation.

Mitigation & Contingency

Mitigation: Verify the assignments table exists and confirm its column structure with the Contact Detail & Edit Screen team which also depends on assignment data (assignment-repository in that feature).

Contingency: If the assignments table is not yet available, implement the AssignmentHistoryRepository with a stub returning empty list and a TODO marker, unblocking the aggregation service while the schema is finalized.