Integrate Reminder and Management Service Calls
epic-certification-management-automation-task-003 — Wire the cron function to invoke CertificationReminderService for certifications expiring in 30/14/7 days and CertificationManagementService for certifications that expired today. Pass structured payloads including certification ID, peer mentor ID, and expiry date. Handle HTTP/RPC response codes and log outcomes per invocation.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 2 - 518 tasks
Can start after Tier 1 completes
Implementation Notes
Implement service call fans-out using Promise.allSettled(certifications.map(cert => callReminderService(cert))) to process all certifications in a window in parallel. This is critical for performance at scale. Define typed payload interfaces (ReminderPayload, ManagementPayload) at the top of services.ts. Use a wrapper function wrapServiceCall(fn, payload) that handles try/catch and logging uniformly so each service call site stays clean.
For logging, structure log lines as JSON objects rather than plain strings — this enables log querying in Supabase Dashboard and external log aggregators. Example: console.log(JSON.stringify({ level: 'INFO', service: 'reminder', certification_id: cert.id, status: result.status, elapsed_ms: elapsed })). Ensure the cron function has the correct permissions to invoke other Edge Functions within the same Supabase project via the service role.
Testing Requirements
Write Deno unit tests in supabase/functions/certification-expiry-cron/services_test.ts. Use a stub Supabase client that captures rpc() or functions.invoke() calls. For each test, seed a mock ExpiryWindowResult with known certification records and assert the correct service is called with the correct payload for each record. Test the error-handling path: inject a stub that returns a 500 response for one invocation and assert that the remaining certifications in the batch are still processed.
Test the exception path: inject a stub that throws a network error for one invocation and assert the batch continues. Write an integration test using a local Supabase instance with real RPC functions stubbed to return success and assert the orchestrateExpiryCheck() function completes without throwing.
Supabase Edge Functions can have cold-start latency that causes the nightly cron to time out when processing large cohorts of expiring certifications, resulting in partial reminder dispatches.
Mitigation & Contingency
Mitigation: Batch the cron processing in chunks of 50 mentors per iteration. Use pagination with a cursor to resume processing if the function is re-invoked. Keep total invocation time well under the Edge Function timeout limit.
Contingency: If timeouts occur in production, split the cron into two separate functions: one for reminders and one for auto-pauses, each with its own schedule offset to reduce peak load.
Certification BLoC covers three distinct workflows (view, renew, enrol) which may lead to an overly complex state machine that is hard to test and maintain, particularly when error states from multiple concurrent operations need to be differentiated in the UI.
Mitigation & Contingency
Mitigation: Use separate sealed state classes per workflow (CertificationViewState, RenewalState, EnrolmentState) composed into a single BLoC state wrapper. Follow the existing BLoC patterns established in the codebase for consistency.
Contingency: If the BLoC grows too complex, split into two BLoCs: CertificationBLoC (view/load) and CertificationActionBLoC (mutations), connected via a shared stream.