Implement FeatureFlagInitializer bootstrap service
epic-organization-feature-flags-runtime-task-001 — Build the FeatureFlagInitializer service that pre-loads the full flag configuration for the authenticated organization immediately after organization selection. The initializer must fetch all flags from the repository, populate the persistent cache, and handle network failures gracefully by falling back to the cached state.
Acceptance Criteria
Technical Requirements
Implementation Notes
Design FeatureFlagInitializer as a plain Dart class with a constructor that accepts FeatureFlagRepository and a Cache abstraction — avoid making it a Riverpod provider itself; let the provider wrap it. This keeps the core logic testable without Riverpod test setup overhead. Use a single `await repository.fetchAllForOrganization(orgId)` call to load all flags at once rather than fetching per-flag-key, which prevents N+1 latency on startup. Expose an `isInitialized` boolean getter so the caller can check state without re-triggering initialization.
Log a structured info message on successful initialization including orgId (not personal data) and flag count for observability.
Testing Requirements
Unit tests for the happy path (flags fetched and cached), the empty-flags path (zero flags returned), and the re-initialization path (calling initialize twice for the same org produces a single cache entry, not duplicates). Integration test verifying the initializer's Supabase query includes the organization_id filter. All tests use mocked FeatureFlagRepository — no real Supabase connection in unit tests.
The feature-flag-initializer must complete before any screen that checks feature flags renders. If the navigation shell is pushed concurrently with initialization (e.g., via a parallel Riverpod provider chain), some screens may query flags before they are loaded and incorrectly receive all-disabled defaults.
Mitigation & Contingency
Mitigation: Gate the main navigation shell render behind the feature-flag-initializer's Future by using a splash/loading screen that awaits the initialization provider. Use Riverpod's ref.watch on an initialization state enum (loading/ready/error) to block rendering.
Contingency: If race conditions are observed in testing, introduce an explicit initialization barrier using a ChangeNotifier or a dedicated `featureFlagsReadyProvider` that the router guard checks before allowing navigation.
If feature-flag-provider is watched by many widgets simultaneously and a flag map refresh triggers all of them to rebuild at once (e.g., after an organization switch), the app could experience a significant UI jank or dropped frames.
Mitigation & Contingency
Mitigation: Use select() on the provider to have each widget watch only the specific flag key it needs rather than the entire map. Ensure the provider uses equality checks so rebuilds only propagate when the specific flag value changes.
Contingency: If rebuild storms are measured via Flutter DevTools, refactor to a family provider keyed by flag key, so each widget subscribes only to its own flag's changes.