high priority medium complexity integration pending integration specialist Tier 3

Acceptance Criteria

After a successful pauseMentor call, CoordinatorNotificationService.notifyStatusChange is invoked with mentor name, new status 'paused', reason, and ISO 8601 timestamp
After a successful reactivateMentor call, all responsible coordinators for the mentor's chapter receive a notification with new status 'active'
After a successful deactivateMentor call, coordinators receive a notification with new status 'inactive' and the deactivation reason
Coordinator lookup uses the assignment entity to resolve the correct coordinator(s) for the given mentorId and organizationId
If CoordinatorNotificationService throws or returns a failure, the status transition result is NOT affected — the MentorStatusService still returns success
Notification dispatch failure is logged with a structured warning (mentor ID, transition type, error message) for operational visibility
Notification payload includes: mentor_id, mentor_display_name, new_status, previous_status, reason, actor_id, timestamp_utc
If no coordinator is found for the mentor, a fallback notification is sent to the organization admin and the absence of coordinator is logged
CoordinatorNotificationService is injected via constructor, not directly instantiated, to allow mocking in tests
The integration does not introduce additional database round-trips beyond what is needed for coordinator lookup

Technical Requirements

frameworks
Flutter
Dart
Riverpod
apis
Supabase PostgreSQL RPC (update_mentor_status)
Supabase REST API
Firebase Cloud Messaging (FCM) API v1 (via CoordinatorNotificationService)
data models
assignment
contact
performance requirements
Notification dispatch must be fire-and-forget (async, non-blocking) so it does not delay the status transition response
Coordinator lookup query must use indexed columns (organization_id, mentor_id) for sub-100ms execution
security requirements
FCM server key must never be present in the Flutter app — notification dispatch must go through a Supabase Edge Function
Notification payloads must not include PII beyond mentor display name — no personnummer, address, or health data
Coordinator lookup must respect RLS — a coordinator must only be notified about mentors within their chapter

Execution Context

Execution Tier
Tier 3

Tier 3 - 413 tasks

Can start after Tier 2 completes

Implementation Notes

Implement the notification dispatch using Future.unawaited() or a fire-and-forget pattern with error boundary to ensure the status result is returned immediately without waiting for notification delivery. The coordinator lookup should reuse the same Supabase client session as the status transition — avoid opening a second session. Define a NotificationPayload value object with all required fields and a toJson() method to keep the payload construction testable. Consider using a try/catch + logger.warn pattern specifically for the notification section, isolated from the transition result.

This decoupling is a business rule: notifications are best-effort, transitions are authoritative.

Testing Requirements

Unit tests using mocked CoordinatorNotificationService verifying: notification is called after each successful transition type, notification is NOT called after a failed transition, failure in notification does not change the return value of the transition method. Integration test verifying the notification payload shape matches what CoordinatorNotificationService expects. Test the fallback behavior when no coordinator is found. Test that notification failure is logged with the correct severity level.

Component
Mentor Status Service
service medium
Epic Risks (3)
medium impact low prob technical

The status state machine must handle race conditions where two concurrent callers (e.g., a mentor self-pausing and a coordinator force-pausing simultaneously) attempt to update the same mentor's status. Without a concurrency guard, both writes could succeed, leaving the audit log in an inconsistent state.

Mitigation & Contingency

Mitigation: Use a Supabase RPC with a row-level lock (SELECT FOR UPDATE) inside a transaction so only one transition wins. Return a clear error to the losing caller. Test with concurrent requests in the integration test suite.

Contingency: If row-level locking proves unreliable in the Supabase environment, add an optimistic-locking version field to peer_mentors and have the service retry up to three times on version conflict before surfacing an error to the caller.

high impact medium prob technical

If the CertificationExpiryJob Edge Function fails silently (network timeout, Supabase cold start), HLF mentors with expired certifications could remain in active status and continue appearing on the chapter website, creating a compliance breach.

Mitigation & Contingency

Mitigation: Implement structured error logging inside the Edge Function, write a monitoring query that checks for mentors with expired certifications still in active status, and set up an alert if any are detected 30 minutes after the scheduled nightly run.

Contingency: Provide a coordinator-accessible manual trigger for the expiry check that can be invoked via the admin interface if the scheduled job is known to have failed. Document the manual recovery procedure for HLF coordinators.

medium impact medium prob dependency

pg_cron registration in Supabase requires superuser-level access that may not be available in all environments (local dev, staging, CI). If the cron job cannot be registered automatically, the Edge Function will never execute on schedule, breaking the HLF certification expiry workflow.

Mitigation & Contingency

Mitigation: Use Supabase's recommended pg_cron setup via the SQL editor migration script and document the exact commands. Validate cron registration in the staging environment as part of the epic's deployment checklist.

Contingency: If pg_cron is unavailable, switch to a Supabase scheduled Edge Function invocation via an external cron service (e.g., a GitHub Actions scheduled workflow calling the Edge Function endpoint with a service-role key) until the pg_cron approach is resolved.