critical priority low complexity backend pending backend specialist Tier 0

Acceptance Criteria

Abstract class ISupabaseSessionManager is defined in lib/core/auth/supabase_session_manager.dart (or equivalent path following project structure)
Interface declares refreshSession() → Future<SessionRefreshResult> with typed result enum (success, networkError, authError)
Interface declares validateCurrentSession() → Future<SessionValidationResult> with typed result enum (valid, expired, revoked, networkUnavailable)
Interface declares signOut() → Future<void>
Interface declares sessionStateStream → Stream<SessionState> where SessionState is a sealed class covering authenticated, refreshing, expired, signedOut states
All method signatures include dartdoc comments explaining contract preconditions, postconditions, and thrown exceptions
SessionState sealed class variants carry typed payloads: authenticated carries AppUser, expired carries expiry DateTime, refreshing carries no payload, signedOut carries SignOutReason enum
No concrete Supabase SDK imports appear in the interface file — it is pure Dart abstract types only
A FakeSupabaseSessionManager stub class is provided alongside the interface for immediate use in other tasks' tests
Interface file compiles cleanly with dart analyze showing zero warnings

Technical Requirements

frameworks
Dart sealed classes (Dart 3.0+)
Riverpod (provider type hints in dartdoc for sessionStateStream)
apis
Supabase Auth SDK (referenced in dartdoc only — not imported in interface file)
performance requirements
Interface introduces zero runtime overhead — abstract class with no concrete logic
security requirements
Interface must not leak Supabase internal session token types into the public contract — use app-level AppSession type
SessionState.authenticated payload must not expose raw JWT string — only structured AppUser type

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Use Dart 3 sealed classes for SessionState and result enums to enable exhaustive switch in consumers — this provides compile-time safety when new states are added. Define all result types (SessionRefreshResult, SessionValidationResult, SessionState, SignOutReason) in the same file or a co-located session_types.dart. Avoid using Either or dartz — keep it plain Dart sealed classes for readability by the whole team. The FakeSupabaseSessionManager should expose a sessionStateController field of type StreamController so tests can push state changes imperatively.

Name the abstract class with an 'I' prefix (ISupabaseSessionManager) to follow the convention already used in the codebase for interfaces.

Testing Requirements

No runtime tests required for the interface definition itself. However, deliver a FakeSupabaseSessionManager that implements ISupabaseSessionManager with controllable behavior (expose StreamController for sessionStateStream, configurable return values for refreshSession and validateCurrentSession).

This fake must itself have a minimal unit test confirming it correctly implements the interface contract — prevents future interface drift breaking mocks silently.

Component
Supabase Session Manager
infrastructure medium
Epic Risks (3)
high impact medium prob technical

Multiple concurrent callers (e.g., SessionResumeManager and a background sync service) could simultaneously detect a near-expired token and each invoke SupabaseSessionManager.refreshSession(), causing duplicate refresh API calls and potentially a token invalidation race condition on the Supabase Auth server. This can result in one caller receiving a valid refreshed token while another receives a 401, causing intermittent authentication failures.

Mitigation & Contingency

Mitigation: Implement a single-flight pattern inside SupabaseSessionManager so that concurrent refresh calls coalesce into one in-flight request. Use a Dart Completer or AsyncMemoizer to ensure all waiters receive the same refreshed token. Write a concurrent integration test to validate the single-flight behaviour.

Contingency: If the single-flight pattern introduces deadlocks or timeout complexity, fall back to a mutex-based lock with a 10-second timeout, logging a warning if the lock is held longer than expected, and triggering a full re-login if the refresh ultimately fails.

high impact low prob security

Supabase Row-Level Security policies evaluate the JWT claims (user_id, role, org_id) on every query. If the refreshed token contains stale or changed claims — for example if a coordinator's role was updated server-side — RLS may silently block data access even though the session appears valid from the client's perspective, causing confusing empty screens rather than an authentication error.

Mitigation & Contingency

Mitigation: After every token refresh, decode the new JWT and compare key claims (role, org_id) with the cached values. If claims have changed, emit a session-claims-changed event that triggers a role re-resolution and navigation reset. Document this behaviour in the SupabaseSessionManager API contract.

Contingency: If claims drift is detected in production and causes data visibility issues, provide a force-refresh mechanism in the UI (pull-to-refresh on home screen) that clears cached role state and re-fetches from Supabase, accompanied by a user-visible toast indicating the session was refreshed.

medium impact medium prob security

Allowing session resumption from cached local token when offline introduces a window where a revoked or invalidated session can still grant app access. For example, if a coordinator deactivates a peer mentor's account while the mentor is offline, the mentor continues to have access until connectivity is restored and the token is validated server-side.

Mitigation & Contingency

Mitigation: Set a maximum offline grace period (e.g., 24 hours) stored alongside the token in SecureSessionStorage. If the grace period is exceeded, force a full credential re-login regardless of connectivity status. Scope offline access to read-only operations only, requiring connectivity for any write that reaches Supabase.

Contingency: If the offline grace period logic is found to be insufficient for compliance, implement remote session invalidation via a lightweight push notification that clears SecureSessionStorage even when the app is backgrounded, using FCM with a data-only message.