Implement PushNotificationDispatcher FCM/APNs wrapper with retry logic
epic-scenario-push-engagement-foundation-task-006 — Implement PushNotificationDispatcher as a thin wrapper around the FCM HTTP v1 API for Android and APNs for iOS. Provide a dispatch(token, title, body, data) method that records delivery status via ScenarioNotificationRepository, retries up to 3 times with exponential backoff on transient failures, and logs permanent failures. Use Dart's http package and handle platform-specific token routing.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 2 - 518 tasks
Can start after Tier 1 completes
Implementation Notes
This dispatcher runs in a Supabase Edge Function (Deno runtime), not in the Flutter app. Use Deno's fetch API rather than Dart's http package for the server-side implementation; the Dart http package reference in the description applies only if a Dart-based server is used. For FCM HTTP v1, authenticate using a Google service account JWT (not the legacy server key). For APNs, use JWT-based authentication with the .p8 key file.
Platform routing: query the device_token table for the token's platform field before dispatching. Exponential backoff: implement as a simple loop with await Future.delayed(Duration(seconds: pow(2, attempt))). Log all retry attempts with attempt number, error code, and token hash (not plain token) for auditability without PII exposure.
Testing Requirements
Write unit tests using flutter_test (or Dart test package for Edge Function logic). Mock the HTTP client to return HTTP 200, HTTP 429 (retry scenario), HTTP 400 (permanent failure), and network timeout. Verify retry count increments correctly and backoff delays are applied. Verify ScenarioNotificationRepository is called with correct status in each scenario.
Verify that after 3 failed retries the record is marked as pending retry. Integration test: deploy to Supabase Edge Function staging environment and send a real test push to a TestFlight device; confirm receipt. Achieve 90% branch coverage on dispatcher logic.
FCM service account key and APNs certificate configuration may be missing or misconfigured in the Supabase Edge Function secrets store, blocking end-to-end push delivery testing until resolved by the infrastructure owner.
Mitigation & Contingency
Mitigation: Raise a credentials-setup task in the project board at epic start; document the exact secret names required in scenario-evaluation-config so the infrastructure owner can provision them independently of development work.
Contingency: Implement a mock push-notification-dispatcher stub that records payloads to the database for local testing, allowing the rest of the feature to proceed while credentials are obtained.
Incorrect RLS policies on the scenario_notifications or notification_preferences tables could allow one user to read or modify another user's notification records, constituting a data privacy breach.
Mitigation & Contingency
Mitigation: Write dedicated RLS policy tests using Supabase's built-in test framework before any application code touches the tables; require a peer security review of all policy definitions before merging.
Contingency: If a policy gap is discovered post-merge, immediately disable the affected table's read policy, notify the security lead, and deploy a hotfix with corrected policies before re-enabling access.
Norwegian Bokmål ARB localisation strings for all scenario message templates may not be available at implementation time, causing content-builder tests to fail and delaying integration.
Mitigation & Contingency
Mitigation: Define all required ARB message keys in a tracked document shared with the content owner at epic kickoff; use English placeholder strings that follow the final format so template injection logic can be tested independently.
Contingency: Ship with English-only strings in the first release and gate Norwegian strings behind a feature flag that is enabled once translations are reviewed and approved.