Define LoginFormBLoC states and events
epic-email-password-login-auth-logic-task-006 — Define the complete set of Bloc events (EmailChanged, PasswordChanged, SubmitPressed, VisibilityToggled) and states (LoginIdle, LoginLoading, LoginSuccess with session+role, LoginCredentialError, LoginNetworkError, LoginRateLimitError, LoginServerError). Granular error states are required to enable discrete live region announcements for accessibility compliance.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 1 - 540 tasks
Can start after Tier 0 completes
Implementation Notes
Place states in lib/features/auth/presentation/bloc/login_state.dart and events in login_event.dart. Use Dart 3 sealed classes for compile-time exhaustiveness in switch expressions in the UI layer — this is critical so the widget tree must handle every state variant or the compiler warns. Do NOT use a single LoginState with an error enum field — granular state types are required for WCAG 2.2 AA live region announcements (each distinct state triggers a Semantics announcement, whereas a single state with changing fields may not). Consider using package:equatable or @freezed for equality and copyWith — consistent with other BLoC classes in the project.
The password visibility toggle (VisibilityToggled event → isPasswordVisible in LoginIdle) must be handled without re-emitting the password value.
Testing Requirements
Unit tests in test/features/auth/presentation/login_form_bloc_test.dart (states/events file itself): (1) Verify LoginIdle, LoginLoading, and each error state can be instantiated. (2) Verify LoginSuccess carries non-null session and role. (3) Verify LoginRateLimitError with retryAfterSeconds: 30 exposes the value. (4) Verify LoginIdle.copyWith(email: 'x') returns a new instance with updated email and unchanged other fields (if copyWith is implemented).
(5) Accessibility test: verify each granular error state has a distinct type (not just a string field) so Semantics widgets can announce specific messages per error type. Use flutter_test, no mocking required.
Supabase GoTrue returns HTTP error codes and string messages that may change between SDK versions. Incorrect or incomplete mapping could cause the wrong user-facing message to be shown (e.g., showing a generic error instead of a specific credential error), violating the plain-language feedback acceptance criteria and potentially exposing security-sensitive information.
Mitigation & Contingency
Mitigation: Pin the supabase_flutter SDK to a specific minor version in pubspec.yaml. Write integration tests that mock the Supabase HTTP layer and assert each error code maps to the correct domain exception. Document the mapping table as a constant in AuthService.
Contingency: If an unrecognized error code is received at runtime, catch it as an UnknownAuthException and display a generic safe message. Alert via crash reporting for triage and SDK update.
If the user taps the sign-in button multiple times rapidly, concurrent authentication requests could result in race conditions: duplicate network calls, out-of-order state emissions, or multiple session tokens being written to secure storage.
Mitigation & Contingency
Mitigation: Use bloc concurrency transformer (droppable or restartable) to ensure only one authentication event is processed at a time. The BLoC should guard against submission while in LoginLoading state.
Contingency: Add a UI-level disable on the submit button when loading state is active as a secondary guard independent of BLoC concurrency control.