critical priority low complexity backend pending backend specialist Tier 0

Acceptance Criteria

A `MentorStatus` enum is defined in Dart with exactly three values: `active`, `paused`, `inactive`
A `StatusTransition` type/record captures `fromStatus`, `toStatus`, `actorId`, `reason`, and `timestamp`
A `MentorStatusRecord` interface/class captures `mentorId`, `currentStatus`, `previousStatus`, `changedAt`, `changedByActorId`, and `reason`
A `kValidTransitions` constant (or equivalent) explicitly lists the three legal transitions: active→paused, paused→active, active→inactive
A pure function `isValidTransition(MentorStatus from, MentorStatus to) → bool` returns true only for the three legal transitions and false for all others (including same-to-same)
paused→inactive transition is explicitly forbidden and returns false from `isValidTransition`
All types are exported from a single barrel file (e.g. `lib/features/mentor_status/mentor_status_types.dart`)
No Supabase or Flutter imports in the types file — pure Dart only

Technical Requirements

frameworks
Dart
data models
MentorStatus
StatusTransition
MentorStatusRecord
performance requirements
`isValidTransition` runs in O(1) using a Set or constant map lookup
security requirements
Transition logic must not be bypassable by casting enum values — use exhaustive switch or map-based lookup
actorId must be typed as a non-nullable String (UUID) to prevent anonymous transitions

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Use a `const Set<(MentorStatus, MentorStatus)>` (Dart record set) for `kValidTransitions` so `isValidTransition` is a O(1) set-contains check. Example: `const kValidTransitions = {(MentorStatus.active, MentorStatus.paused), (MentorStatus.paused, MentorStatus.active), (MentorStatus.active, MentorStatus.inactive)}`. Avoid if-else chains — the set approach is self-documenting and extensible. Use Dart's `sealed class` or `enum` with extension methods for `MentorStatus` to add helpers like `.isTerminal` (returns true for `inactive`).

Keep this file as pure-Dart domain logic with zero dependencies — it will be imported by both the Flutter app layer and the Supabase edge function layer.

Testing Requirements

Pure Dart unit tests (no widget pump needed). Test cases: (1) all 9 possible from/to combinations of the 3 status values — assert exactly 3 return true and 6 return false; (2) verify paused→inactive explicitly returns false; (3) verify active→active, paused→paused, inactive→inactive return false (self-transitions forbidden); (4) verify MentorStatusRecord can be constructed with all required fields; (5) verify StatusTransition serialises and deserialises correctly (toJson/fromJson if implemented). 100% branch coverage expected given the small surface area.

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.