high priority medium complexity testing pending testing specialist Tier 4

Acceptance Criteria

On service instantiation, the mock Realtime channel is opened with a filter containing the correct `user_id` value
When the mock channel emits a simulated INSERT event with a valid notification JSON payload, the service's notification stream emits a correctly typed `Notification` object
When the mock channel emits an INSERT event with a malformed payload, the service does not crash and either skips the event or emits an error to the stream (behavior is tested explicitly)
When the auth state change stream emits a new session (user re-authenticated), the service unsubscribes the existing channel and opens a new subscription
When auth state emits a signed-out event, the service closes the subscription and stops emitting notifications
Calling `dispose()` cancels the Realtime channel subscription and closes all internal StreamControllers without throwing
After `dispose()`, the notification stream is closed (no further events emittable)
connectionStatus stream emits `connected` when the channel reports a connected state
connectionStatus stream emits `disconnected` when the channel reports a disconnected or error state
All tests pass without actual Supabase network connections

Technical Requirements

frameworks
flutter_test
mockito or mocktail
apis
Supabase Realtime channel API
data models
Notification
RealtimeConnectionStatus
SupabaseRealtimeSubscriptionService
performance requirements
All tests complete within 10 seconds
No real async delays in tests — use fake async or synchronous stream controllers
security requirements
Test fixtures must not contain real user IDs
Mock auth state must not expose real credentials

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Implementation Notes

The key design challenge is making the service testable: inject the Supabase Realtime channel factory and the auth state stream via constructor parameters rather than creating them internally. This enables full mock substitution in tests. For stream assertions, prefer `expectLater(service.notifications, emits(isA()))` over manually collecting stream events. For the dispose test, call `dispose()` and then assert the stream is closed using `expect(service.notifications.isBroadcast ?

... : stream.isClosed)` or by attempting to listen and catching the closed stream error. The malformed payload test is important for resilience — the service should catch JSON parse errors per-event and log them rather than crashing the stream.

Testing Requirements

Unit tests using flutter_test with fake/mock Supabase Realtime channel and a fake auth state stream. Place tests in `test/features/notifications/data/supabase_realtime_subscription_service_test.dart`. Use `StreamController` fakes to simulate channel events and auth state changes — this avoids async timing issues. Test groups: (1) subscription lifecycle (open on init, correct filter), (2) event mapping (valid INSERT, malformed INSERT), (3) auth state reactivity (re-auth, sign-out), (4) dispose correctness, (5) connectionStatus stream states.

Use `expect(stream, emitsInOrder([...]))` or `expectLater` for async stream assertions. Verify dispose with a `verify(mockChannel.unsubscribe()).called(1)` assertion.

Component
Supabase Realtime Subscription Service
infrastructure medium
Epic Risks (3)
high impact medium prob technical

Supabase Realtime channels on mobile networks can drop silently. If reconnection logic is flawed, users miss notifications without knowing it, undermining the audit-trail guarantee.

Mitigation & Contingency

Mitigation: Implement exponential-backoff reconnection with a maximum of 5 retries; expose a channel-status stream to the BLoC so it can trigger a full-fetch fallback when the channel reconnects after a gap.

Contingency: If Realtime reliability proves insufficient in production, fall back to polling the repository every 60 seconds as a background supplement to the Realtime channel.

high impact medium prob security

Coordinator and org-admin RLS expansions require joining user_roles and org_memberships tables. An incorrect policy could expose notifications to wrong users or block legitimate access entirely.

Mitigation & Contingency

Mitigation: Write dedicated RLS integration tests for each role (peer mentor, coordinator, org admin) using separate Supabase test projects. Review policies with the security checklist before merging.

Contingency: If an RLS defect is discovered post-deployment, disable the expanded-scope policy and revert to user-scoped-only access while a corrected migration is prepared and tested.

medium impact medium prob integration

JSONB payload structure may vary across notification types created by different Edge Functions (reminder, expiry, scenario, pause). Missing or renamed fields will cause runtime parse failures.

Mitigation & Contingency

Mitigation: Define a canonical NotificationPayload union type in a shared schema document. Each Edge Function must validate its payload against this schema before inserting. Add fallback parsing with default values in the domain model.

Contingency: Wrap all payload parsing in try/catch and log malformed payloads to a monitoring channel; render a generic notification item rather than crashing when the payload cannot be parsed.