high priority high complexity testing pending testing specialist Tier 4

Acceptance Criteria

Test environment starts a local Supabase instance via Docker Compose and the test suite connects successfully before any test case runs
ScenarioEvaluationConfig is loaded from environment variables or a test config file — no hardcoded production values in the test
ScenarioNotificationContentBuilder produces a non-empty localised title and body for at least two scenario types (Norwegian and English) as verified by assertion before dispatch
PushNotificationDispatcher successfully sends a notification payload to a test FCM endpoint stub (e.g., WireMock or a local HTTP echo server) and receives a 200 OK response
After successful dispatch, a record exists in the scenario_notification_records Supabase table with status = DELIVERED and the correct scenario_type and recipient_id
After a simulated FCM failure, a record exists in scenario_notification_records with status = FAILED — verified by querying Supabase directly via the test client
ScenarioDeepLinkRouter resolves the FCM response payload to the correct named route for each tested scenario type — verified by route name assertion
The entire integration test suite completes in under 60 seconds on a developer laptop
Test teardown drops all seeded records from scenario_notification_records to leave the local database clean after each test run
A README or inline comment documents how to start the local Supabase Docker environment before running the tests

Technical Requirements

frameworks
Flutter
flutter_test
Supabase Flutter SDK
Docker / Docker Compose
apis
Supabase REST API (local Docker instance)
FCM HTTP v1 API stub (WireMock or local echo server)
ScenarioNotificationRepository
PushNotificationDispatcher
ScenarioNotificationContentBuilder
ScenarioDeepLinkRouter
ScenarioEvaluationConfig
data models
ScenarioNotificationRecord (id, scenario_type, recipient_id, status, dispatched_at)
ScenarioEvaluationConfig
NotificationContent
DeepLinkPayload
performance requirements
Full integration test suite completes in under 60 seconds
Local Supabase Docker container must start and be reachable within 30 seconds of docker compose up
Database queries in assertions must complete in under 500ms
security requirements
Local Supabase uses test credentials only — never connect integration tests to a production or staging Supabase project
FCM API key in test environment must be a placeholder value pointing to the local stub, not a real Firebase project key
Test records seeded into Supabase must be clearly marked (e.g., recipient_id prefixed with 'test-') and cleaned up after each run

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Implementation Notes

Use supabase_flutter with a custom Supabase URL pointing to localhost:54321 (default local Supabase port). Load the local anon key from a .env.test file that is committed to the repo without secrets (use the well-known local dev anon key). For the FCM stub, the simplest approach is a Dart shelf server started in setUpAll() that returns 200 OK for success tests and 500 for failure tests, then torn down in tearDownAll(). Configure PushNotificationDispatcher to accept an injectable base URL for the FCM endpoint so it can be redirected to the local stub.

The integration test is the authoritative proof that all five foundation components (Config, Builder, Dispatcher, Repository, Router) compose correctly — design it to catch contract mismatches (e.g., the repository expecting a different status enum value than the dispatcher produces).

Testing Requirements

Integration tests using flutter_test with a real local Supabase instance (Docker). Tests are not widget tests — they exercise the Dart business logic and repository layers directly. Organise into a single group('End-to-end notification dispatch') with setUp() starting Docker and connecting Supabase client, and tearDown() cleaning seeded records. Run at least 3 scenario types through the full pipeline.

Use a WireMock or local HTTP stub for FCM to avoid real Firebase calls. Assert database state by querying Supabase directly in the test (not via the repository abstraction) to catch any repository mapping bugs. These tests must run in CI with Docker available — add a GitHub Actions job or Makefile target that starts Supabase before running the test suite.

Component
Push Notification Dispatcher
infrastructure medium
Dependencies (8)
Write unit tests for ScenarioDeepLinkRouter covering: cold-start payload resolves correct route with full back-stack, foreground payload navigates without duplicate back-stack entries, unknown scenario_type falls back to notification centre, malformed payload does not crash the router, and each known scenario_type maps to the expected route. Use flutter_test and mock the navigator. epic-scenario-push-engagement-foundation-task-013 Implement ScenarioNotificationContentBuilder that generates FCM/APNs title and body strings for each scenario type. Support Norwegian (nb) and English (en) locales. Inject personalised context values: daysInactive, sessionCount, daysToExpiry, mentorFirstName. Define a ScenarioMessageTemplate model with locale-keyed strings and a buildMessage(scenarioType, locale, context) factory method. epic-scenario-push-engagement-foundation-task-007 Implement ScenarioDeepLinkRouter to parse incoming push notification payloads (scenario_type, entity_id, target_route) and resolve the correct in-app navigation target. Handle both cold-start (app launched from terminated state) and foreground scenarios. Ensure back-stack integrity by pushing the correct ancestor routes before the destination. Integrate with the existing GoRouter or Navigator 2.0 setup. epic-scenario-push-engagement-foundation-task-008 Write unit tests for NotificationPreferencesRepository covering: default opted-in behaviour when no row exists, upsert idempotency, multi-scenario preference retrieval, and Supabase error propagation. Use flutter_test and mock the Supabase client. Achieve minimum 90% branch coverage for the repository class. epic-scenario-push-engagement-foundation-task-009 Write unit tests for ScenarioNotificationRepository covering: recordNotificationSent persists correct fields, updateDeliveryStatus transitions, cooldown upsert and retrieval, and getPendingRetries filters by retry_count and status. Mock Supabase client. Cover error handling paths including network exceptions and constraint violations. epic-scenario-push-engagement-foundation-task-010 Write unit tests for ScenarioNotificationContentBuilder covering: correct Norwegian and English string output per scenario type, correct interpolation of all context values (daysInactive, sessionCount, daysToExpiry, mentorFirstName), fallback to English when locale is unsupported, and exception on unknown scenario type. Use flutter_test with parameterised test cases. epic-scenario-push-engagement-foundation-task-011 Write unit tests for PushNotificationDispatcher covering: successful FCM dispatch records DELIVERED status, first-attempt transient failure triggers retry with backoff, exhausted retries record FAILED status, permanent FCM error skips retries and logs failure, and delivery status is always written to the repository regardless of outcome. Mock the HTTP client and ScenarioNotificationRepository. epic-scenario-push-engagement-foundation-task-012 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. epic-scenario-push-engagement-foundation-task-006
Epic Risks (3)
high impact medium prob dependency

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.

high impact low prob security

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.

medium impact medium prob dependency

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.