critical priority medium complexity database pending database specialist Tier 1

Acceptance Criteria

SupabasePauseStatusRecordRepository class implements PauseStatusRecordRepository and is registered in the dependency injection layer
fetchActivePauseRecord(mentorId) queries peer_mentor_profiles filtered by mentor_id and status = 'paused', returns PauseStatusRecord or null when no active pause exists
fetchActivePauseRecord returns null (not an error) when the mentor has no pause record — callers distinguish 'not paused' from 'error'
resolveCoordinator(mentorId) queries the org membership table and returns a CoordinatorRelationship for the primary coordinator
All queries are RLS-compliant: tested with a coordinator-role JWT and a peer-mentor-role JWT, confirming correct row visibility in each case
Network errors are caught and mapped to typed failures (not raw Supabase exceptions exposed to callers)
watchPauseStatus(mentorId) returns a Supabase Realtime stream that emits updated PauseStatusRecord on row change
Repository methods complete within 2 seconds under normal network conditions in staging

Technical Requirements

frameworks
Flutter
Supabase Flutter SDK
Riverpod
apis
Supabase PostgREST REST API
Supabase Realtime API
data models
PauseStatusRecord
CoordinatorRelationship
peer_mentor_profiles
org_memberships
performance requirements
fetchActivePauseRecord must complete within 2 seconds on a standard mobile connection
Use .select() with explicit column lists — never SELECT * — to minimize payload size
Realtime subscription must reconnect automatically on network interruption
security requirements
All queries executed with the authenticated user's JWT — never use the service role key on the client
RLS policies must prevent coordinators from reading pause records of mentors outside their chapter
No raw SQL strings constructed via string interpolation (use parameterized PostgREST filters)

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Inject the SupabaseClient via Riverpod provider — do not instantiate it directly in the repository. Use the Supabase Flutter SDK's `.from('peer_mentor_profiles').select('id, mentor_id, status, paused_at, resumed_at, reason, created_at, updated_at').eq('mentor_id', mentorId).eq('status', 'paused').maybeSingle()` pattern so a missing row returns null rather than throwing. For Realtime, use `.stream(primaryKey: ['id']).eq('mentor_id', mentorId)` and map each emitted list to a nullable PauseStatusRecord. Wrap all Supabase calls in try/catch and map PostgrestException and SocketException to the appropriate typed failures defined in task-001.

Confirm with the DB team which table and column names are canonical for org membership before writing queries.

Testing Requirements

Unit tests using a mocked Supabase client: (1) fetchActivePauseRecord returns PauseStatusRecord when a matching row exists. (2) fetchActivePauseRecord returns null when no row matches (not an exception). (3) fetchActivePauseRecord maps a Supabase exception to the correct typed failure. (4) resolveCoordinator returns the expected CoordinatorRelationship for a single-chapter mentor.

(5) watchPauseStatus emits updated records on mock stream push. Integration tests in staging: run each query with coordinator-role and peer-mentor-role JWTs and assert RLS filtering is correct.

Component
Pause Status Record Repository
data low
Epic Risks (3)
high impact medium prob integration

The org membership table structure used to resolve coordinator relationships may differ from what the repository assumes, causing incorrect coordinator lookup or missing rows for mentors in multi-chapter scenarios.

Mitigation & Contingency

Mitigation: Review the existing org membership table schema and RLS policies before writing repository queries. Align query logic with the patterns already used by peer-mentor-status-repository and multi-chapter-membership-service.

Contingency: If schema differs, add an adapter layer in the repository that normalises the membership resolution and document the discrepancy for the data team. Fall back to coordinator lookup via the feature's own stored coordinator_id field if org membership join fails.

high impact medium prob technical

Device tokens stored in the database may be stale or unregistered, causing FCM dispatch failures that silently drop coordinator notifications — the primary coordination safeguard of this feature.

Mitigation & Contingency

Mitigation: Implement token validation on every dispatch call and handle FCM's NOT_REGISTERED error by flagging the token as invalid in the database. Reuse the token refresh pattern already established by fcm-token-manager.

Contingency: If push delivery fails after retry, ensure the in-app notification record is always written regardless of push outcome so coordinators can still see the event in the notification centre.

medium impact low prob technical

The optional reason field may contain special characters, emoji, or non-Latin scripts that exceed the 200-character byte limit when FCM encodes the payload, causing delivery failures.

Mitigation & Contingency

Mitigation: Enforce the 200-character limit on Unicode code point count, not byte count, in the payload builder. Add a unit test with multi-byte input strings.

Contingency: If an oversized payload is detected at dispatch time, strip the reason field from the push notification body and note 'See in-app notification for full reason' to preserve delivery.