Define CertificationBLoC Events and States
epic-certification-management-automation-task-006 — Define all BLoC events (LoadCertification, RecordRenewal, EnrolInCourse) and the corresponding state classes (CertificationInitial, CertificationLoading, CertificationLoaded, CertificationError, RenewalSuccess, EnrolmentSuccess). Implement Equatable for all state and event classes. Establish the barrel export file for the BLoC module.
Acceptance Criteria
Technical Requirements
Implementation Notes
Use Dart's `sealed` keyword (available from Dart 3.0) on the base event and state classes — this enables exhaustive pattern matching in the BLoC and produces compiler warnings if a new event/state is added without being handled. File structure convention: `lib/features/certification/bloc/certification_event.dart`, `certification_state.dart`, `certification_bloc.dart`. The `Certification` domain model should be defined in `lib/features/certification/models/certification.dart` separately — do not inline it in the state file, as it will be reused by the repository and UI layers. If the `Certification` model does not yet exist, create a minimal version with the fields needed by the states and add a TODO comment marking it for enrichment by the service layer task.
Follow the project's existing BLoC naming conventions — check adjacent BLoC modules for file and class naming patterns before writing.
Testing Requirements
Write pure Dart unit tests (no widget tree needed). Test 1: assert `LoadCertification('id-1') == LoadCertification('id-1')` returns true. Test 2: assert `LoadCertification('id-1') != LoadCertification('id-2')` returns true. Test 3: assert `CertificationLoaded(certification: c1) == CertificationLoaded(certification: c1)` where c1 uses Equatable.
Test 4: assert `CertificationError(message: 'err') != CertificationLoading()`. Test 5: assert `RenewalSuccess.props` contains `updatedCertification`. These tests run in under 100ms and require no mocking. Place in `test/certification/certification_bloc_definitions_test.dart`.
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.