high priority medium complexity backend pending backend specialist Tier 3

Acceptance Criteria

Abstract class PauseManagementService is defined with method signatures: pauseMentor(String mentorId, PauseReason reason, {String? triggeredBy}) → Future<void>, resumeMentor(String mentorId, {String? resumedBy}) → Future<void>, isMentorPaused(String mentorId) → Future<bool>, getPauseStatus(String mentorId) → Future<PauseStatus?>
PauseReason is an enum with at least: certificationExpired, manualByCoordinator, manualBySelf — extensible for future reasons
PauseStatus is a data class with fields: mentorId, isPaused, reason (PauseReason?), pausedAt (DateTime?), pausedBy (String?), notes (String?)
SupabasePauseManagementService implements PauseManagementService and writes pause state to the peer_mentors table (or a dedicated peer_mentor_pauses table) via the Supabase client
A triggerAutoPauseOnCertificationExpiry(String mentorId) method is exposed as a stable hook for CertificationManagementService to call; it internally calls pauseMentor with PauseReason.certificationExpired
When a mentor is paused with reason certificationExpired, their coordinator is notified via the PushNotificationService (injected dependency)
isMentorPaused and pauseReason are readable by the coordinator's dashboard and the mentor's own profile screen without elevated permissions
pauseMentor and resumeMentor require coordinator or admin role (enforced by RLS or service-layer role check)
All pause state transitions are audit-logged (at minimum: mentorId, oldStatus, newStatus, reason, changedBy, changedAt)
Unit tests cover: auto-pause on expiry, coordinator manual pause, resume flow, and idempotent double-pause (no error if already paused)

Technical Requirements

frameworks
Flutter
Supabase Flutter SDK
Riverpod (DI)
BLoC (for coordinator UI state)
apis
Supabase PostgREST
PushNotificationService (internal)
data models
PauseStatus
PauseReason (enum)
peer_mentors (Supabase table, pause-related columns)
CertificationModel
performance requirements
isMentorPaused must return in under 100ms (single row lookup by primary key)
Audit log writes must be non-blocking (fire-and-forget with error logging, not blocking the pause flow)
security requirements
pauseMentor and resumeMentor must validate the calling user's role server-side via RLS — do not rely solely on client-side role checks
Audit log must not be mutable by non-admin users (append-only RLS policy)
triggerAutoPauseOnCertificationExpiry must only be callable from within the certification domain service layer, not directly from UI code

Execution Context

Execution Tier
Tier 3

Tier 3 - 413 tasks

Can start after Tier 2 completes

Implementation Notes

Add pause-related columns to peer_mentors if they don't exist: is_paused (boolean, default false), pause_reason (text, nullable), paused_at (timestamptz, nullable), paused_by (uuid, nullable). Alternatively, use a dedicated peer_mentor_pauses table for full audit history — prefer this approach if multiple pause periods need to be tracked over time. Inject PushNotificationService into SupabasePauseManagementService via Riverpod so it can send coordinator notifications without tight coupling. Define a clear contract in the abstract class's doc comments specifying which exceptions are thrown and when.

The triggerAutoPauseOnCertificationExpiry method should be the single entry point for all certification-driven pauses — avoid calling pauseMentor directly from the certification service. The HLF organisation requirement states that an expired certificate should remove the mentor from the local branch website automatically — document this as a downstream effect of the pause status that the visualisation/website integration must listen for via Supabase Realtime.

Testing Requirements

Unit tests (flutter_test with mocked Supabase and mocked PushNotificationService): (1) pauseMentor with certificationExpired reason updates pause status and triggers a coordinator notification; (2) isMentorPaused returns true after pause and false after resume; (3) double-calling pauseMentor is idempotent (does not throw, does not create duplicate audit entries); (4) resumeMentor clears the pause reason and updates pausedAt to null; (5) triggerAutoPauseOnCertificationExpiry delegates to pauseMentor with the correct PauseReason. Integration test: create a certification, expire it, call triggerAutoPauseOnCertificationExpiry, and assert the database row reflects the paused state. Verify the coordinator notification is sent exactly once (check idempotency via cert_notification_log).

Component
Pause Management Service
service medium
Epic Risks (3)
high impact medium prob integration

HLF Dynamics portal webhook API contract may be undocumented, subject to change, or require a separate authentication flow not yet agreed upon with HLF. If the contract changes post-implementation, the sync service silently fails and expired peer mentors remain on public listings.

Mitigation & Contingency

Mitigation: Obtain the official Dynamics webhook specification and test credentials from HLF before starting HLFDynamicsSyncService implementation. Agree on a versioned webhook contract and request a staging endpoint for integration testing.

Contingency: If the contract is unavailable, stub the sync service behind a feature flag and ship without Dynamics sync initially. Queue sync events locally and replay once the contract is confirmed.

high impact medium prob security

Supabase RLS policies for certifications must correctly scope data to the coordinator's chapter without leaking cross-organisation data, particularly complex in multi-chapter membership scenarios. A misconfigured policy could expose peer mentor PII to wrong coordinators.

Mitigation & Contingency

Mitigation: Write RLS policies against the established org-hierarchy schema used by other tables. Peer review all policies before migration deployment. Add integration tests that assert cross-organisation data isolation using test accounts with different org scopes.

Contingency: If a policy gap is discovered post-merge, immediately disable the affected query endpoint and apply a hotfix migration. Audit access logs in Supabase for any cross-org data access events.

medium impact low prob technical

Storing renewal history as a JSONB field rather than a normalised table simplifies queries but makes retrospective schema changes (adding fields to history entries) harder and could cause issues if history grows very large for long-tenured mentors.

Mitigation & Contingency

Mitigation: Define a versioned JSONB entry schema (include a schema_version field in each entry) so future migrations can transform old entries. Add a size guard in the repository to warn if renewal_history exceeds 500 entries.

Contingency: If JSONB approach proves limiting, add a normalised certification_renewal_events table and migrate history entries in a background job, keeping the JSONB field as a read cache.