critical priority high complexity testing pending testing specialist Tier 10

Acceptance Criteria

Seeding 5 peer mentors with distinct states (inactive-eligible, milestone-eligible, cert-expiry-eligible, opted-out, in-cooldown) results in exactly 3 notification records after one scheduler run
The opted-out user has zero notification records after the scheduler run
The in-cooldown user has zero new notification records after the scheduler run
A second consecutive scheduler invocation (same clock state) creates zero additional records due to cooldown enforcement
After advancing the simulated clock beyond the cooldown window, a third scheduler invocation creates new records for previously suppressed eligible users
Each dispatched notification record contains the correct scenario_type matching the peer mentor's state
The scheduler completes without throwing uncaught exceptions for any seeded state variant
Test teardown restores the database to clean state (zero rows for all test user IDs)
End-to-end test suite passes in under 90 seconds

Technical Requirements

frameworks
flutter_test
Dart test package
Supabase Dart client
apis
Supabase REST API
Supabase Edge Function invocation (or direct Dart scheduler function call)
Supabase Auth service role for test teardown
data models
notification_preferences (opted_in gate)
scenario_notification_records (dispatch audit log)
scenario_notification_cooldowns (deduplication state)
peer_mentors (activity state, milestone count, certification_expiry_date)
performance requirements
Full E2E test suite completes in under 90 seconds
Scheduler invocation under test must complete in under 10 seconds for 5 seeded users
security requirements
Dedicated test Supabase project or local emulator — never production
Service role credentials via environment variables only
Synthetic UUIDs for all test user_ids — no real user data

Execution Context

Execution Tier
Tier 10

Tier 10 - 11 tasks

Can start after Tier 9 completes

Implementation Notes

The scheduler must accept an injectable clock (DateTime or a Clock abstraction) so tests can advance time without sleeping. If the scheduler is a Supabase Edge Function, invoke it via the Supabase Functions client with a testMode flag that bypasses push delivery and uses a mock push provider that records calls in-memory. Structure seeding as a helper method seedPeerMentorScenarios() that returns a map of scenario_type → user_id so assertions can reference the correct users without hardcoding UUIDs. Pay special attention to the cooldown advancement: update the cooldown record's last_triggered_at directly in the database to simulate time passing rather than relying on sleep().

This test is the contract test for the scheduler — if it passes, the scheduler is correct by definition.

Testing Requirements

Single end-to-end test file with three sequential phases in one test: Phase 1 — seed and first scheduler run with assertions on record count and opted-out/cooldown exclusions. Phase 2 — immediate second scheduler run asserting zero new records (cooldown active). Phase 3 — advance clock abstraction past cooldown window, run scheduler again, assert new records created for previously suppressed users. Use group() blocks in flutter_test to separate phases for readable output.

Assert both positive cases (records exist with correct fields) and negative cases (opted-out and cooldown users have no records) via direct Supabase queries. Include a comprehensive tearDown that deletes all rows matching test user IDs from all three tables.

Component
Scenario Edge Function Scheduler
infrastructure medium
Epic Risks (3)
high impact medium prob technical

The scenario-edge-function-scheduler must evaluate all active peer mentors within the 30-second Supabase Edge Function timeout. For large organisations, a sequential evaluation loop may exceed this limit, causing partial runs and missed notifications.

Mitigation & Contingency

Mitigation: Design the trigger engine to batch mentor evaluations using database-side SQL queries (bulk inactivity check via a single query rather than per-mentor calls), and add a performance test against 500 mentors during development. Document the evaluated mentor count per scenario type in scenario-evaluation-config to allow selective scenario execution per run.

Contingency: If single-run execution is insufficient, split evaluation into per-scenario-type scheduled functions (inactivity check, milestone check, expiry check) on separate cron schedules, dividing the computational load across multiple invocations.

high impact low prob technical

A race condition between concurrent scheduler invocations or retried cron triggers could cause the same scenario notification to be dispatched multiple times to a mentor, severely degrading trust in the feature.

Mitigation & Contingency

Mitigation: Implement cooldown enforcement using a database-level upsert with a unique constraint on (user_id, scenario_type, cooldown_window_start) so that a second invocation within the same window is rejected at the persistence layer rather than the application layer.

Contingency: Add an idempotency key derived from (user_id, scenario_type, evaluation_date) to the notification record insert; if a duplicate key violation is caught, log it as a warning and skip dispatch without error.

medium impact medium prob integration

The trigger engine queries peer mentor activity history across potentially multiple organisations and chapters. RLS policies configured for app-user roles may block the Edge Function's service-role queries, or query performance may degrade on large activity tables.

Mitigation & Contingency

Mitigation: Confirm the Edge Function runs with the Supabase service role key (bypassing RLS) and add composite indexes on (user_id, activity_date) to the activity tables before implementing the inactivity detection query.

Contingency: If service-role access is restricted by organisational policy, implement a dedicated database function (SECURITY DEFINER) that performs the inactivity aggregation and is callable by the Edge Function with limited scope.