high priority low complexity backend pending backend specialist Tier 0

Acceptance Criteria

CredentialValidator.validateEmail(String email) returns a ValidationResult object with isValid: bool and errorMessage: String?
errorMessage is null when isValid is true
Valid emails pass: user@example.com, user.name+tag@sub.domain.org, user@domain.co.uk
Invalid emails fail with a non-null errorMessage: empty string, missing @, missing domain, consecutive dots (user..name@domain.com), leading/trailing spaces (trim is NOT applied — caller's responsibility)
Error messages are returned as localization keys (e.g., 'validation.email.invalid') not hardcoded strings, so they can be resolved via the app's l10n system
Function is pure: identical input always produces identical output, no network calls, no state mutation
Regex pattern is documented with a reference to the RFC 5322 subset being implemented
Performance: 10,000 sequential calls complete in under 100ms (no expensive backtracking)

Technical Requirements

frameworks
Flutter
Dart
data models
ValidationResult (isValid: bool, errorMessage: String?, fieldName: String)
performance requirements
Validation executes synchronously in under 1ms per call
Regex must not exhibit catastrophic backtracking on adversarial inputs (test with 200-character malformed strings)
security requirements
Do not use the email as a signal for account enumeration — validation is purely syntactic, never queries the database
Input length should be capped at 320 characters (RFC 5321 maximum) before regex matching

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Use a well-known, conservative RFC 5322 subset regex rather than attempting full RFC compliance (which is impractical in a single regex). A reliable pattern: r'^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$'. Document explicitly that this is a syntactic check only — Supabase will perform authoritative validation during sign-up. Return a typed ValidationResult sealed class or simple data class — do not return String?

(null = valid) as that pattern is less readable. Keep CredentialValidator as a final class with only static methods for easy testing and use in both BLoC event handlers and Flutter FormField validators. Localization keys should follow the app's existing l10n convention.

Testing Requirements

Unit tests using flutter_test covering: (1) 10+ valid email formats; (2) 10+ invalid formats including empty string, whitespace-only, missing @, double @, missing TLD, consecutive dots; (3) boundary: exactly 320 characters returns isValid true if otherwise valid; (4) 321 characters returns isValid false; (5) localization key is returned (not a resolved string) for error messages. No integration tests needed — pure function. Performance test: loop 10,000 calls and assert duration under 100ms.

Component
Credential Validator
service low
Epic Risks (2)
high impact low prob integration

Supabase client initialization may fail silently in certain Flutter environments if environment variables are missing or the anon key is rotated, leading to runtime null-pointer errors throughout the auth layer.

Mitigation & Contingency

Mitigation: Add explicit assertion checks during app startup that verify the Supabase client is initialized before the router resolves. Document required --dart-define keys in the project README and add a CI step that validates their presence.

Contingency: Implement a fallback initialization error screen with a clear message and a retry button. Log initialization failures to crash reporting immediately.

medium impact medium prob technical

The flutter_secure_storage package behaviour differs between iOS Keychain and Android Keystore implementations. On Android, biometric-enrolled devices may require additional authentication to read stored tokens, causing unexpected session read failures.

Mitigation & Contingency

Mitigation: Test the repository on Android devices with and without biometric enrollment early in development. Use accessibility options in flutter_secure_storage to configure whether biometric authentication is required for storage access.

Contingency: If biometric-gated storage causes regressions, fall back to a non-biometric storage option for session tokens (reserving biometric-gated storage for higher-sensitivity credentials only).