high priority high complexity testing pending backend specialist Tier 5

Acceptance Criteria

Test suite seeds mentor records at all defined threshold tiers (e.g., 90, 60, 30, 14, 0 days before expiry) and verifies each triggers the correct notification type
Edge function invoked in test mode produces in-app notification records with accurate threshold_tier, mentor_id, certificate_id, and created_at values in Supabase
FCM payload enqueue assertions confirm deep link format matches the navigation route for the certificate detail screen
Lapsed mentor (expired certificate, unacknowledged) is suppressed from all mentor listing queries after pipeline execution
Acknowledgement service integration: calling the ack endpoint clears the active banner record and writes an audit row with correct user_id, timestamp, and notification_id
Tests are idempotent: running the suite twice produces no duplicate notification records
Test mode flag prevents real FCM delivery and real Supabase cron scheduling while still exercising all business logic paths
All threshold boundary conditions tested: one day before each tier boundary and one day after
Negative path: mentor with valid certificate generates no notification records
Test execution completes within 60 seconds on CI
All tests pass in isolation and when run as a full suite

Technical Requirements

frameworks
Flutter (flutter_test)
Supabase Edge Functions (Deno)
Supabase local dev (supabase start)
apis
Supabase REST API (mentor records, notification records, audit records)
FCM HTTP v1 API (mocked in test mode)
Expiry check edge function HTTP endpoint
data models
mentor_certificates
notifications
notification_audit_log
mentor_visibility_state
performance requirements
Full integration suite completes in under 60 seconds
Database seed + teardown adds no more than 5 seconds per test case
No test leaves orphaned rows — teardown must be deterministic
security requirements
Test mode must be gated behind an environment variable or secret — never activatable in production
Seeded test records must use non-real personal identifiers (no real BankID data)
Service role key used only in test context, never committed to source

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

Use Supabase's local development stack (supabase start) to run a local Postgres + Edge Function runtime — do not hit production or staging. Create a dedicated test schema or use row-level teardown via a service role client. The edge function must accept a test_mode: true body parameter that swaps the real FCM sender for a no-op stub and routes enqueue writes to a test_fcm_queue table instead of the live queue. Threshold tier constants must be imported from a shared config module (not hardcoded in tests) so a single constant change propagates everywhere.

For the visibility suppression assertion, query through the same RLS-aware view used by the Flutter app (not raw table) to ensure the test validates the real access path. Consider a test helper function `seedMentorAtDaysBeforeExpiry(int days)` to keep test bodies readable. Group tests by pipeline stage (orchestrator → visibility → ack) so failures are immediately attributable to a specific service.

Testing Requirements

Integration tests written in Dart using flutter_test and Supabase local emulator (supabase start). Each test case seeds the required mentor certificate rows directly via Supabase service role client, invokes the edge function via HTTP with a test-mode header, then asserts database state using select queries. Use a shared setUp/tearDown that truncates affected tables between cases. Cover: (1) all threshold tier rows generate correct notification records, (2) FCM enqueue table has correct payload shape, (3) lapsed mentor visibility suppression query returns empty set, (4) ack service clears banner and writes audit row, (5) idempotency — second invocation produces no new rows.

Use group() blocks to separate orchestration, visibility, and acknowledgement concerns. Target 100% coverage of all pipeline branches defined in the orchestrator service.

Component
Certificate Expiry Check Edge Function
infrastructure medium
Dependencies (5)
Within the coordinator acknowledgement service, implement the audit trail write: persist a structured acknowledgement event record containing coordinator ID, mentor ID, certificate type, notification threshold tier, acknowledgement timestamp, and any free-text note. Store in a dedicated audit log table and expose a read endpoint for compliance reporting. epic-certificate-expiry-notifications-orchestration-services-task-010 Connect the course enrollment prompt service to the expiry notification orchestrator so that notification payloads for lapsed and 7-day-warning tiers include the enrollment deep link. The orchestrator calls the prompt service per mentor record and embeds the resulting URL into both the FCM push payload and the in-app notification record. epic-certificate-expiry-notifications-orchestration-services-task-013 Extend the mentor visibility suppressor to support reactivation: when a previously suppressed mentor's certificate is renewed and detected by the repository, restore their public listing visibility. Ensure reactivation is atomic and logs the reinstatement event with timestamp, certificate ID, and acting user for coordinator audit trail. epic-certificate-expiry-notifications-orchestration-services-task-008 Add structured error handling to the expiry check edge function: catch downstream service failures, log execution summaries (mentor counts per tier, notification counts dispatched, suppressions applied, errors encountered) to a persistent execution log table, and emit an alert if the function exits with a non-zero error count. Ensure partial failures do not abort the entire run. epic-certificate-expiry-notifications-orchestration-services-task-016 Register the expiry check edge function on the Supabase pg_cron schedule to run daily at a defined UTC time (e.g. 02:00 UTC). Document the cron expression, set up environment variable injection for service-role keys, and configure execution timeout limits. Verify the function is listed in Supabase's scheduled functions dashboard. epic-certificate-expiry-notifications-orchestration-services-task-015
Epic Risks (4)
high impact medium prob technical

If the daily edge function runs more than once in a 24-hour window due to a Supabase scheduling anomaly or manual re-trigger, the orchestrator could dispatch duplicate push notifications to the same mentor and coordinator for the same threshold, eroding user trust.

Mitigation & Contingency

Mitigation: Implement idempotency at the notification record level using a unique constraint on (mentor_id, threshold_days, certification_id). The orchestrator checks for an existing record before dispatching. Use a database-level upsert with ON CONFLICT DO NOTHING.

Contingency: If duplicate notifications are reported in production, add a rate-limiting guard in the edge function that aborts if a notification for the same mentor and threshold was created within the last 20 hours, and add an alerting rule to Supabase logs for duplicate dispatch attempts.

medium impact medium prob scope

The mentor visibility suppressor relies on the daily edge function to detect expiry and update suppression_status. A mentor whose certificate expires at midnight may remain visible for up to 24 hours if the cron runs at a fixed time, violating HLF's requirement that expired mentors disappear promptly.

Mitigation & Contingency

Mitigation: Schedule the edge function to run at 00:05 UTC to minimise lag after midnight transitions. Additionally, the RLS policy can include a direct date comparison (certification_expiry_date < now()) as a secondary predicate that does not rely on suppression_status, providing real-time enforcement at the database level.

Contingency: If the cron lag is unacceptable after launch, implement a Supabase database trigger on the certifications table that fires on UPDATE of expiry_date and calls the suppressor immediately, reducing lag to near-zero for renewal and expiry events.

medium impact low prob integration

The orchestrator needs to resolve the coordinator assigned to a specific peer mentor to dispatch coordinator-side notifications. If the assignment relationship is not normalised or is missing for some mentors, coordinator notifications will silently fail.

Mitigation & Contingency

Mitigation: Query the coordinator assignment from the existing assignments or user_roles table before dispatch. Log a structured warning (missing_coordinator_assignment: mentor_id) when no coordinator is found. Add a data quality check in the edge function that reports mentors without coordinators.

Contingency: If coordinator assignments are missing at scale, fall back to notifying the chapter-level admin role for the mentor's chapter, and surface a data quality report to the admin dashboard showing mentors without assigned coordinators.

medium impact low prob dependency

The course enrollment prompt service generates deep-link URLs targeting the course administration feature. If the course administration feature changes its deep-link schema or the Dynamics portal URL structure changes, enrollment prompts will navigate to broken destinations.

Mitigation & Contingency

Mitigation: Define the deep-link contract between the certificate expiry feature and the course administration feature as a shared constant in a cross-feature navigation config. Version the deep-link schema and validate the generated URL format in unit tests.

Contingency: If the deep-link breaks in production, the course enrollment prompt service should gracefully fall back to opening the course administration feature root screen with a query parameter indicating the notification context, allowing the user to manually locate the correct course.