high priority medium complexity testing pending testing specialist Tier 5

Acceptance Criteria

Integration test suite is located in `test/integration/pause_notification_integration_test.dart`
Test setup seeds a minimal test Supabase project (or a local Supabase instance) with: one organisation, one coordinator user with a device token, one peer mentor user with a device token, and one paused assignment linking them
Test 1 — repository fetch: `PauseNotificationRepository.fetchPauseContext(assignmentId)` returns a non-null `PauseNotificationContext` containing the seeded assignment, coordinator device token, and mentor device token
Test 2 — payload construction: coordinator and mentor payloads built from the fetched context have correct `type`, `assignment_id`, and `deep_link_path` data fields
Test 3 — dispatcher call: `FcmNotificationDispatcher.dispatchPause(coordinatorPayload, mentorPayload)` completes without throwing; FCM responses are captured via a stub or test double that records calls
Test 4 — in-app record: after dispatch, the `notifications` table in the test database contains two rows for the assignment — one with `recipient_role: 'coordinator'` and one with `recipient_role: 'peer_mentor'`, both with `status: 'sent'`
Test 5 — missing device token: when the coordinator has no registered device token, dispatcher skips FCM call for coordinator and in-app record is still created with `status: 'no_device'`
Teardown deletes all seeded rows after each test to prevent cross-test pollution
All integration tests are skipped automatically when the `SUPABASE_TEST_URL` environment variable is not set, with a clear skip message

Technical Requirements

frameworks
Flutter
Dart
flutter_test
apis
Supabase PostgreSQL 15
Supabase Auth
Firebase Cloud Messaging (FCM) API v1
data models
assignment
device_token
contact
performance requirements
Each integration test must complete within 10 seconds
Database seed and teardown combined must not exceed 3 seconds
security requirements
Test Supabase credentials stored only in CI/CD environment variables — never committed to source control
FCM dispatcher uses a test double in CI to avoid sending real push notifications
Test database must be isolated from production — use a dedicated test project or schema

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

Create a `FakeFcmDispatcher` that implements the same `FcmDispatcherInterface` as the real dispatcher, storing dispatched payloads in a list for assertion. Inject this fake via constructor or provider override in tests — do not patch globals. For the Supabase seed, use the service-role client to bypass RLS during setup/teardown only; the system-under-test must use a regular user-scoped client to validate that RLS does not block legitimate reads. Use `skipIf(Platform.environment['SUPABASE_TEST_URL'] == null)` at the top of the test file.

Document the required environment variables in a comment block at the top of the test file.

Testing Requirements

Integration tests using flutter_test with a real (or local Docker) Supabase instance. Use `setUpAll` to establish a Supabase client with the test service-role key from environment variables. Use a `FakeFcmDispatcher` test double that records payloads instead of calling FCM. Each `test` block should call `setUp` and `tearDown` for row-level seeding and cleanup.

Group tests with `group('pause_notification_integration')`. Tag with `@Tags(['integration'])` so they can be excluded from fast unit test runs.

Component
FCM Notification Dispatcher
infrastructure medium
Epic Risks (3)
high impact medium prob integration

The org membership table structure used to resolve coordinator relationships may differ from what the repository assumes, causing incorrect coordinator lookup or missing rows for mentors in multi-chapter scenarios.

Mitigation & Contingency

Mitigation: Review the existing org membership table schema and RLS policies before writing repository queries. Align query logic with the patterns already used by peer-mentor-status-repository and multi-chapter-membership-service.

Contingency: If schema differs, add an adapter layer in the repository that normalises the membership resolution and document the discrepancy for the data team. Fall back to coordinator lookup via the feature's own stored coordinator_id field if org membership join fails.

high impact medium prob technical

Device tokens stored in the database may be stale or unregistered, causing FCM dispatch failures that silently drop coordinator notifications — the primary coordination safeguard of this feature.

Mitigation & Contingency

Mitigation: Implement token validation on every dispatch call and handle FCM's NOT_REGISTERED error by flagging the token as invalid in the database. Reuse the token refresh pattern already established by fcm-token-manager.

Contingency: If push delivery fails after retry, ensure the in-app notification record is always written regardless of push outcome so coordinators can still see the event in the notification centre.

medium impact low prob technical

The optional reason field may contain special characters, emoji, or non-Latin scripts that exceed the 200-character byte limit when FCM encodes the payload, causing delivery failures.

Mitigation & Contingency

Mitigation: Enforce the 200-character limit on Unicode code point count, not byte count, in the payload builder. Add a unit test with multi-byte input strings.

Contingency: If an oversized payload is detected at dispatch time, strip the reason field from the push notification body and note 'See in-app notification for full reason' to preserve delivery.