Implement FeatureFlagProvider Riverpod AsyncNotifier
epic-organization-feature-flags-runtime-task-004 — Create the FeatureFlagProvider as a Riverpod AsyncNotifier that resolves the active organization context, delegates flag loading to the initializer and repository, and builds an in-memory map of resolved flag states keyed by flag constants. The provider must invalidate and re-build the map when the active organization changes.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 3 - 413 tasks
Can start after Tier 2 completes
Implementation Notes
Declare the provider with `@riverpod` annotation if using riverpod_generator, or as a top-level `final featureFlagProvider = AsyncNotifierProvider
This pattern composes cleanly with AsyncValue's `whenData` and `value` accessors.
Testing Requirements
Unit tests using ProviderContainer with overrideWithValue: (1) happy path — mock initializer completes, mock repository returns 3 flags, assert all 3 keys present in map with correct boolean values; (2) org switch — override activeOrgProvider with a different orgId after initial build, assert provider rebuilds and map reflects new org's flags; (3) empty flags — mock returns empty list, assert map is empty and isEnabled returns false for any key; (4) loading state — mock initializer that never completes, assert provider is in loading state. All tests use flutter_test with no real Riverpod internals replaced.
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.