high priority medium complexity testing pending testing specialist Tier 3

Acceptance Criteria

Test setup: two org fixtures (org-A, org-B) and two user fixtures (user-A in org-A, user-B in org-B) are created in the test Supabase instance via service role client before the test runs
Step 1: ReminderConfigRepository.updateReminderDays(org-A, 7) succeeds; subsequent fetch returns reminder_days = 7 for org-A
Step 2: An assignment record is inserted for org-A with last_contact_date = DateTime.now().subtract(Duration(days: 10)); AssignmentContactTrackingRepository.fetchOverdueAssignments(org-A, thresholdDays: 7) returns this assignment in the result list
Step 3: InAppNotificationRepository.insertNotification for the overdue assignment in org-A returns a non-null notification id
Step 4: InAppNotificationRepository.markAsRead(notificationId, user-A) succeeds; subsequent fetchUnread(user-A, org-A) returns an empty list
Step 5: PushNotificationService.sendToUser(user-A, ...) with mock dispatch (real service in test mode) completes without exception
RLS cross-org test: fetchUnread(user-A, org-B) returns empty list (user-A's data not visible under org-B's RLS policy)
RLS cross-org test: fetchOverdueAssignments(org-B, thresholdDays: 7) returns only org-B's assignments, not org-A's overdue assignment
Test teardown: all fixture data (orgs, users, assignments, notifications, reminder configs) is deleted after test completion to leave the test database clean
Integration test is tagged with @Tags(['integration']) and is excluded from default flutter test run; invoked explicitly via flutter test --tags integration

Technical Requirements

frameworks
Flutter
flutter_test
Supabase Flutter SDK (real client against test instance)
Riverpod (for DI wiring in test)
apis
Supabase REST API (test instance)
Supabase Auth (service role for fixture setup)
Supabase RLS policies (verified through test assertions)
data models
ReminderConfig
AssignmentContactTracking
OverdueAssignment
InAppNotification
performance requirements
Full integration test scenario must complete in under 30 seconds against a local Supabase instance
Test setup (fixture creation) and teardown (fixture deletion) must be wrapped in try/finally to guarantee cleanup even on test failure
security requirements
Test Supabase credentials (URL, anon key, service role key) must be loaded from environment variables or a .env.test file never committed to source control
Service role key (used only in setup/teardown for fixture creation) must not be embedded in the Flutter app runtime — only used in test bootstrapping code
RLS cross-org assertions are mandatory acceptance criteria, not optional — their absence means the test does not validate the security model

Execution Context

Execution Tier
Tier 3

Tier 3 - 413 tasks

Can start after Tier 2 completes

Implementation Notes

Structure the test using a TestFixtureManager helper class that creates and tracks all inserted rows, then deletes them in reverse insertion order during teardown. This prevents orphaned records from accumulating across failed test runs. For RLS validation, create two SupabaseClient instances authenticated as user-A and user-B respectively, then run cross-org queries and assert empty results. Do not rely on Supabase throwing errors for RLS rejection — it returns empty sets silently.

The integration test is the authoritative proof that RLS policies are correctly configured; if unit tests pass but integration tests fail on RLS assertions, the database migration is incorrect. Coordinate with the database migration task to ensure the test database schema matches production. Run this test suite as a mandatory gate in the CI/CD pipeline before merging to main.

Testing Requirements

Integration test using real Supabase connection (local docker-based instance preferred; staging acceptable). Use Supabase's service role client exclusively for fixture setup/teardown (bypasses RLS intentionally for test data management). Use org-scoped user clients for the actual test scenario assertions to exercise RLS. Tag the test file with @Tags(['integration']) so it is excluded from CI unit test runs and only executed in a dedicated integration test step.

Document the required environment variables (SUPABASE_TEST_URL, SUPABASE_TEST_ANON_KEY, SUPABASE_TEST_SERVICE_ROLE_KEY) in the test file header. The PushNotificationService must use its mock implementation in this test (real FCM dispatch is not needed for data layer validation).

Dependencies (8)
Write unit tests for the PushNotificationService wrapper covering: sendToUser happy path, sendToTopic happy path, FCM token not found handling, platform channel error handling, and mock stub verification. Verify the service correctly delegates to FCM token manager and does not expose raw FCM internals to callers. epic-assignment-follow-up-reminders-foundation-task-011 Implement the PushNotificationService infrastructure wrapper that encapsulates FCM token management and push dispatch. Expose sendToUser(userId, title, body, data) and sendToTopic(topic, payload) methods. Integrate with the existing FCM token manager. Handle platform-specific notification channels for Android and iOS. Provide a mock implementation for testing environments. epic-assignment-follow-up-reminders-foundation-task-007 Write unit tests for ReminderConfigRepository using flutter_test and a Supabase mock client. Cover: successful fetch, update of reminder_days, update of escalation_days, RLS rejection for wrong org, and network error handling. Assert typed domain models are returned and exceptions are properly surfaced. epic-assignment-follow-up-reminders-foundation-task-008 Write unit tests for InAppNotificationRepository covering: insert a notification record, mark as read, fetch unread for user scoped to org, fetch by assignment, delete old records, and RLS enforcement for cross-org access. Use flutter_test with Supabase mock. Verify correct SQL filter parameters are passed in each query. epic-assignment-follow-up-reminders-foundation-task-009 Write unit tests for AssignmentContactTrackingRepository covering: update last_contact_date, fetch overdue assignments with various threshold values, empty result when no assignments are overdue, org scoping enforcement, and index-backed query efficiency. Include edge case where last_contact_date is null (never contacted). epic-assignment-follow-up-reminders-foundation-task-010 Implement the ReminderConfigRepository Dart class that reads and writes reminder_days and escalation_days from the org_settings table via the Supabase client. Expose typed methods: fetchConfig(orgId), updateReminderDays(orgId, days), updateEscalationDays(orgId, days). Handle Supabase errors and map to domain exceptions. epic-assignment-follow-up-reminders-foundation-task-004 Implement the InAppNotificationRepository Dart class backed by the notification_log table. Expose methods: insertNotification(record), markAsRead(notificationId), fetchUnreadForUser(userId, orgId), fetchByAssignment(assignmentId), and deleteOlderThan(cutoff). Use Riverpod provider for injection. Ensure all queries filter by org_id for data isolation. epic-assignment-follow-up-reminders-foundation-task-005 Implement the AssignmentContactTrackingRepository Dart class that queries the assignments table for last_contact_date data. Expose methods: updateLastContactDate(assignmentId, date), fetchOverdueAssignments(orgId, thresholdDays), fetchAssignmentContactSummary(assignmentId). Queries must include org_id scope and leverage the compound index created in the migration task. epic-assignment-follow-up-reminders-foundation-task-006
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.