high priority medium complexity testing pending testing specialist Tier 2

Acceptance Criteria

Token registration test: calling registerToken(userId, fcmToken) persists the token to the fcm_tokens Supabase table and overwrites any pre-existing token for the same userId
Token refresh test: simulating a token rotation event (Firebase onTokenRefresh) triggers a re-registration that replaces the old token in Supabase within one retry cycle
Single message delivery test: sendNotification(userId, payload) reaches the mock FCM HTTP endpoint and the delivery_attempts table receives an entry with status='delivered' and a non-null delivered_at timestamp
Batch delivery test: sendBatch([userId1, userId2, userId3], payload) dispatches three FCM messages and all three delivery records are written correctly without duplication
Transient failure retry test: when the mock FCM endpoint returns HTTP 503 on the first two attempts, the sender retries and eventually records status='delivered' after a successful third attempt
Permanent failure test: when the mock FCM endpoint returns HTTP 404 (invalid token), the sender records status='failed', increments retry_count to the configured maximum, and does not retry further
Logout token clearance test: calling clearToken(userId) removes the row from fcm_tokens in Supabase and subsequent sendNotification calls for that userId produce a 'no_token' result without throwing an unhandled exception
Delivery tracking persistence test: every attempt (success and failure) writes a row to the delivery_attempts table with correct notification_id, user_id, attempt_number, status, and timestamps
All tests pass in CI using either a Firebase emulator or a dedicated test Firebase project, with no dependency on the production FCM endpoint

Technical Requirements

frameworks
flutter_test
Dart test package
mockito or mocktail for HTTP mocking
firebase_messaging (Flutter SDK)
supabase_flutter
apis
FCM HTTP v1 API (mocked via http mock client or local emulator)
Supabase REST API (test project instance)
Firebase Auth emulator (optional, for token lifecycle simulation)
data models
fcm_tokens (user_id, token, updated_at)
delivery_attempts (id, notification_id, user_id, attempt_number, status, delivered_at, error_code, retry_count)
performance requirements
Full integration test suite completes in under 60 seconds
Batch delivery test with 3 recipients completes in under 5 seconds against the mock endpoint
security requirements
Test Firebase credentials must be stored in CI environment variables, never committed to source
Test Supabase URL and anon key must be a dedicated test project, not production
FCM tokens used in tests must be synthetic/emulator-generated values

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Use Dart's http package with an injectable HttpClient so the FCM endpoint URL can be swapped for a mock server in tests. The Supabase client should point to a dedicated test project (configure via environment variables or a test-specific initialization block). For the retry logic tests, use fake_async from the test package to advance time without real delays — this keeps tests fast and deterministic. When testing logout clearance, ensure the test first inserts a row into fcm_tokens, calls clearToken, then queries Supabase directly to assert the row no longer exists.

For batch delivery, assert both FCM call count (via mock) and Supabase delivery_attempts row count. If a Firebase emulator is not available in CI, mock the FCM HTTP v1 endpoint using nock or a lightweight Dart HTTP interceptor. Document in the test file which environment variables are required to run the suite.

Testing Requirements

Integration tests only (no unit mocks of the sender itself — the sender IS the subject under test). Use a real Supabase test project for database assertions; use an HTTP mock client or Firebase local emulator for FCM endpoint simulation. Cover the full happy path, transient retry path, permanent failure path, and logout clearance path. Assert database state after each scenario using direct Supabase queries.

Tests must be deterministic and isolated: each test case seeds its own token data and cleans up afterward using a tearDown hook. Target 100% branch coverage of FcmPushNotificationSender public methods. Include at least one test that validates the retry back-off interval does not exceed the configured maximum delay.

Component
FCM Push Notification Sender
infrastructure medium
Epic Risks (3)
high impact medium prob technical

The RLS policy predicate that checks certification_expiry_date and suppression_status on every coordinator list query could cause full table scans at scale, degrading response time for coordinator contact list screens across all chapters.

Mitigation & Contingency

Mitigation: Add a partial index on (certification_expiry_date, suppression_status) filtered to active mentors. Benchmark the policy predicate against a representative data set (500+ mentors) during development using EXPLAIN ANALYZE on Supabase staging.

Contingency: If the index does not resolve the performance issue, introduce a computed boolean column is_publicly_visible that is updated by the mentor_visibility_suppressor service and indexed separately, shifting the predicate cost to write time rather than read time.

medium impact medium prob integration

FCM device tokens become invalid when users reinstall the app or switch devices. If the token management strategy does not handle token refresh reliably, notification delivery will silently fail for a significant portion of the user base without surfacing errors.

Mitigation & Contingency

Mitigation: Implement the FCM token refresh callback in the Flutter client to upsert the latest token to Supabase on every app launch. Store token with a last_refreshed_at timestamp. The FCM sender should handle UNREGISTERED error codes by deleting stale tokens.

Contingency: If token staleness becomes widespread, add a token health check that forces re-registration during the expiry check edge function run by querying mentors whose token was last refreshed more than 30 days ago and triggering a silent push to prompt re-registration.

medium impact low prob integration

The certification expiry and notification record tables may have column naming or constraint conflicts with existing tables in the peer mentor status and certification management features, causing migration failures in shared Supabase environments.

Mitigation & Contingency

Mitigation: Audit existing table schemas for user_roles, certifications, and notification tables before writing migrations. Prefix new columns with expiry_ to avoid collisions. Run migrations against a clean Supabase branch environment before merging.

Contingency: If a conflict is found post-merge, apply ALTER TABLE migrations to rename conflicting columns and issue a hotfix migration. Communicate schema changes to all dependent feature teams via a shared migration changelog.