Initialize Supabase Auth Client Singleton
epic-email-password-login-foundation-task-001 — Create the Supabase Auth client singleton that reads SUPABASE_URL and SUPABASE_ANON_KEY from environment configuration and exposes a single initialized GoTrueClient instance. Implement lazy initialization with a factory constructor and ensure thread-safe access across the app lifecycle.
Acceptance Criteria
Technical Requirements
Implementation Notes
Use the established supabase_flutter package pattern: call Supabase.initialize() in main() before runApp(), then access via Supabase.instance.client. If a custom wrapper class is needed (e.g., to allow DI in tests), use a thin facade over Supabase.instance rather than reimplementing GoTrueClient. Dart does not have true thread safety concerns at the VM level for single-isolate apps, but if background isolates are used, pass the client reference explicitly — do not rely on the singleton across isolate boundaries. Mark the initialize() method @visibleForTesting if needed for test overrides.
Testing Requirements
Unit tests using flutter_test: (1) verify singleton identity across multiple getInstance() calls; (2) verify StateError is thrown when accessed before initialize(); (3) verify that initialize() called twice does not re-create the client. Integration test: initialize with real env credentials and assert client.auth is non-null. No mocking of the Supabase client itself in integration tests — use a real staging project.
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.
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).