medium priority low complexity testing pending testing specialist Tier 1

Acceptance Criteria

Test: sendToUser(userId, title, body, data) happy path — mock FCM token manager returns a valid token — asserts the underlying dispatch method is called exactly once with the correct token, title, body, and data payload
Test: sendToTopic(topic, payload) happy path — asserts the underlying FCM topic send method is called once with correct topic string and payload map
Test: sendToUser where mock FCM token manager returns null or throws TokenNotFoundException — asserts PushNotificationService throws FcmTokenNotFoundException (typed, not generic Exception)
Test: sendToUser where the underlying platform channel throws a PlatformException — asserts the service catches it and rethrows as a typed PushNotificationException with the original PlatformException as cause
Test: verify that no FirebaseMessaging or RemoteMessage types appear in the PushNotificationService public interface — confirmed by the fact that all test interactions use only domain types (userId: String, title: String, data: Map)
Test: MockPushNotificationService (from task-007) correctly records calls — assert that after calling sendToUser, MockPushNotificationService.capturedCalls contains the expected entry
All tests are pure unit tests using flutter_test and mocktail; no Firebase TestLab or real device required
Test file passes flutter test with zero errors and zero analyzer warnings

Technical Requirements

frameworks
Flutter
flutter_test
mockito or mocktail
apis
FCM token manager interface (mocked)
Firebase Messaging (mocked at abstraction boundary)
data models
FcmToken
NotificationPayload
FcmTokenNotFoundException
PushNotificationException
performance requirements
All unit tests complete in under 2 seconds
security requirements
Test must assert that data payload does not leak sensitive fields — if the service sanitizes data before dispatch, test the sanitization logic

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

The abstraction boundary is the most architecturally significant aspect of these tests. If FirebasePushNotificationService is implemented correctly, its unit tests should not require firebase_messaging to be initialized (which requires a real app context). All Firebase calls should be behind a thin FcmDispatcher interface that is mockable. If the implementation does not have this abstraction, the tests will fail to run in a pure Dart unit test environment — this is a useful design pressure.

For the MockPushNotificationService self-test (last acceptance criterion), ensure the mock's capturedCalls list is reset in setUp() to prevent test ordering dependencies.

Testing Requirements

Unit tests only. The key test here is the interface boundary test — confirm no FCM-specific types leak through the PushNotificationService API. This is best verified by ensuring the test file itself has zero imports of firebase_messaging or firebase_core; if those imports are needed to set up mocks, the abstraction is leaking. Use a MockFcmTokenManager stub to control token resolution behavior.

For the PlatformException wrapping test, throw a PlatformException from the mock dispatch method and assert the caught exception is PushNotificationException with cause set.

Component
Push Notification Service
infrastructure medium
Epic Risks (3)
high impact medium prob integration

Adding last_contact_date to the assignments table may conflict with existing RLS policies or trigger-based logic that monitors the assignments table. If the migration is not carefully reviewed, existing assignment management features could break in production.

Mitigation & Contingency

Mitigation: Review all existing triggers, policies, and foreign key constraints on the assignments table before writing the migration. Run the migration against a staging Supabase instance with production-like data and execute the full existing test suite before merging.

Contingency: Roll back the migration using Supabase's versioned migration history. Apply the schema change as an additive-only migration (nullable column with default) to ensure zero downtime and reversibility.

medium impact medium prob dependency

The PushNotificationService wraps an existing FCM integration whose internal API contract may have changed or may not expose the payload formatting required for deep-link CTAs. Misalignment discovered late delays the dispatch service epic.

Mitigation & Contingency

Mitigation: Before implementing the wrapper, read the existing push notification integration code and confirm the method signatures, payload structure, and token management model. Agree on a stable interface contract in a shared Dart abstract class.

Contingency: If the existing service is incompatible, implement a thin adapter layer that translates reminder payloads to the existing service's format, isolating the reminder feature from upstream changes.

high impact low prob security

Incorrect RLS policies on notification_log could allow coordinators to read reminder records belonging to peer mentors in other chapters, exposing sensitive assignment information across organisational boundaries.

Mitigation & Contingency

Mitigation: Write explicit RLS policies with integration tests that assert cross-chapter queries return zero rows. Use Supabase's built-in auth.uid() and join through the org membership tables to scope all queries.

Contingency: If a policy gap is discovered post-merge, immediately disable the affected table's SELECT policy, deploy a corrected policy, and audit recent queries in Supabase logs for any cross-boundary reads.