critical priority low complexity integration pending fullstack developer Tier 2

Acceptance Criteria

After the user selects an organization, the app calls FeatureFlagInitializer.initialize(orgId) before navigating to the main shell route
A loading indicator is shown during initialization — the user cannot interact with gated content while flags are loading
If initialization completes (from network or fallback), the app proceeds to the main shell without showing any error dialog
If the user selects a different organization from the organization switcher, the initializer is called again with the new orgId and the flag state is refreshed before the shell re-renders
No feature-gated widget renders before FeatureFlagProvider has a resolved (non-loading) state — verified by widget test with a delayed initializer mock
The loading state during flag initialization is visually indistinguishable from normal app startup — no jarring second loading screen

Technical Requirements

frameworks
Flutter
Riverpod
Dart
go_router or Navigator 2.0
apis
Supabase Auth (organization context from JWT)
data models
activity_type
performance requirements
Total time from organization selection tap to main shell visible must remain under 4 seconds on 3G
Flag initialization must not add more than 1 second to existing organization selection latency
security requirements
Navigation to any gated route must be blocked until FeatureFlagProvider state is non-loading
Organization context for initialization must come from the auth session, not from navigation route parameters
ui components
Loading indicator (full-screen or progress overlay)
Organization selection screen (existing, to be extended with post-selection hook)

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

In go_router, use a redirect function on the shell route that checks FeatureFlagProvider state: if loading, redirect to a `/loading` or `/splash` route; if resolved, allow navigation. This is cleaner than blocking in the organization selection screen itself and avoids duplicated loading logic for org-switch flows. In Riverpod, wrap FeatureFlagInitializer in a FutureProvider keyed by orgId so that Riverpod's built-in AsyncValue loading/data/error states drive the UI — avoid manual `isLoading` booleans. Use `ref.watch` in the router redirect so the redirect re-evaluates automatically when initialization completes.

Testing Requirements

Widget tests using Riverpod's ProviderScope overrides: (1) mock FeatureFlagInitializer that delays 500ms — assert loading UI is shown and main shell is not visible; (2) mock that completes immediately — assert main shell renders without loading state; (3) mock that simulates org switch mid-session — assert provider invalidates and re-initializes. Integration test verifying the router does not push the main shell route until FeatureFlagProvider is in a resolved state.

Component
Feature Flag Initializer
infrastructure low
Epic Risks (2)
high impact medium prob technical

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.

medium impact low prob technical

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.