high priority medium complexity testing pending testing specialist Tier 2

Acceptance Criteria

Test: updateLastContactDate(assignmentId, orgId, date) asserts that the update targets the correct row (eq on id AND org_id) and sets last_contact_date to the correct ISO-8601 string
Test: fetchOverdueAssignments(orgId, thresholdDays: 7) with mock returning 2 assignments whose last_contact_date is 8 and 10 days ago asserts list length = 2 and both are typed OverdueAssignment domain models with correct fields
Test: fetchOverdueAssignments(orgId, thresholdDays: 30) with mock returning 1 assignment asserts correct threshold is applied (cutoff date = now minus 30 days)
Test: fetchOverdueAssignments where mock returns empty list asserts that an empty List<OverdueAssignment> is returned (not null, not exception)
Test: fetchOverdueAssignments where mock returns assignments with null last_contact_date asserts these are included in overdue results (null = never contacted = always overdue)
Test: fetchOverdueAssignments with wrong orgId (mock returns empty) asserts org scoping is applied — query filter includes org_id = orgId
Test: updateLastContactDate with a network error mock asserts a typed RepositoryException is thrown
Threshold boundary test: assignment with last_contact_date exactly equal to the cutoff — asserts whether it is included or excluded (document which behavior is correct in test description)
All tests pass with flutter test; test file is named assignment_contact_tracking_repository_test.dart

Technical Requirements

frameworks
Flutter
flutter_test
mockito or mocktail
apis
Supabase Flutter SDK (mocked)
data models
AssignmentContactTracking
OverdueAssignment
performance requirements
Test suite for this repository completes in under 3 seconds
Comment in the fetchOverdueAssignments test noting that the real query relies on an index on (org_id, last_contact_date) — verifiable in the integration test (task-012)
security requirements
org_id filter must always be present in fetchOverdueAssignments query — test must verify the filter parameter is passed

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

The medium complexity rating comes from the threshold date calculation. The repository computes a cutoff DateTime as DateTime.now().subtract(Duration(days: thresholdDays)) and passes it to the Supabase query as a filter. To make this testable, inject a Clock or DateTimeProvider into the repository constructor (default: () => DateTime.now()) so tests can pass a fixed clock. The null last_contact_date case maps to a SQL OR condition: last_contact_date IS NULL OR last_contact_date < cutoff.

Ensure the repository implementation covers both branches and the test mocks both scenarios. For the boundary case, decide and document whether the threshold is strict (lt) or inclusive (lte) — this affects reminder frequency and should match product requirements from the likeperson.md spec (Blindeforbundet: 10-day automatic reminder).

Testing Requirements

Unit tests with flutter_test and mocktail. The null last_contact_date edge case is the most important test in this file — it encodes a product decision (never-contacted = always overdue) that must be explicitly tested and documented. Use a helper buildMockAssignment({DateTime? lastContactDate}) factory to reduce boilerplate across test cases.

For threshold boundary testing, use a fixed 'now' via dependency injection or a clock abstraction to make cutoff calculations deterministic. Aim for full branch coverage including null check, empty result, and exception paths.

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.