critical priority low complexity infrastructure pending infrastructure specialist Tier 5

Acceptance Criteria

orgSelectionServiceProvider is defined and provides a stable OrgSelectionService instance
currentOrgProvider is defined and returns the currently selected Organization (or null if none selected)
labelProvider is defined as an AsyncNotifierProvider and returns the active OrgLabelMap
OrgLabelsProvider's Riverpod provider declares ref.watch(currentOrgProvider) so it auto-invalidates when the org changes
All providers are registered in a single, well-organized provider file (e.g., org_providers.dart) — no scattered provider definitions
ProviderScope at the app root wraps all providers without overrides in production
Test overrides (via ProviderContainer or ProviderScope overrides) work correctly for all registered providers
No circular dependencies exist between providers — dependency graph is a DAG
Widget tests can override currentOrgProvider and labelProvider in isolation without triggering Supabase calls

Technical Requirements

frameworks
Flutter
Riverpod (Provider, AsyncNotifierProvider, NotifierProvider)
data models
Organization
OrgSelectionService
OrgLabelsProvider
OrgLabelMap
performance requirements
Provider registration must complete synchronously at app startup — no async initialization in the provider definition itself
Provider instances must be singletons within the ProviderScope lifetime
security requirements
Providers must not retain data after user logout — implement a logout invalidation sequence that resets currentOrgProvider and labelProvider

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

Organize all org-related providers in `lib/providers/org_providers.dart`. Use Riverpod code generation (@riverpod annotation) if the project already uses it, for consistency. Provider dependency chain: `orgRepositoryProvider` → `orgPersistenceRepositoryProvider` → `orgSelectionServiceProvider` → `currentOrgProvider` → `labelProvider`. The `currentOrgProvider` should be a simple `Provider` that reads from `orgSelectionServiceProvider.getSelectedOrganization()` — kept separate from `orgSelectionServiceProvider` so widgets can watch org changes without holding a reference to the full service.

Critically, expose `labelProvider` as the public API for all UI consumption — widgets should never directly access `OrgLabelsProvider` instance methods. Add a `logoutProvider` or integrate org cleanup into the existing auth logout flow by calling `ref.invalidate` on all org providers when the auth state changes to unauthenticated.

Testing Requirements

Use flutter_test with Riverpod's ProviderContainer for isolated provider graph testing. Test cases: (1) changing currentOrgProvider value causes labelProvider to rebuild, (2) all providers can be overridden in a ProviderContainer for widget tests, (3) no circular dependency errors thrown when building the provider graph, (4) after logout invalidation, currentOrgProvider returns null and labelProvider returns loading/null state, (5) overriding orgSelectionServiceProvider with a mock does not affect unrelated providers. Run provider dependency graph validation as part of the test suite.

Component
Organization Selection Service
service low
Epic Risks (2)
high impact medium prob technical

The OrgLabelsProvider must be fully initialized before any UI widget renders organization-specific text. If the service triggers label initialization asynchronously and the UI builds before the labels stream emits, widgets will briefly display raw label keys instead of human-readable text, which constitutes a WCAG 2.2 AA failure for screen readers that announce whatever text is present at render time.

Mitigation & Contingency

Mitigation: Design the OrgSelectionService.select() method to await OrgLabelsProvider initialization before completing its Future — callers receive a resolved future only after labels are ready. Use an AsyncValue loading state to gate UI rendering via Riverpod's when() pattern.

Contingency: If awaiting initialization causes perceivable UI lag, implement an optimistic render with a skeleton loading state that is announced by the live-region-announcer as 'Loading organization content' so screen readers do not announce raw keys.

medium impact medium prob integration

If the label definitions loaded from the backend for each organization do not match the label key registry used in the UI, widgets will fall back to raw keys silently. This is particularly harmful for Blindeforbundet users relying on VoiceOver, where a raw key announced by a screen reader is incomprehensible.

Mitigation & Contingency

Mitigation: Define a compile-time label key registry (enum or const strings) and assert at OrgLabelsProvider initialization that all required keys are present in the loaded map. Log a structured warning for any missing key and substitute a human-readable fallback string rather than the raw key.

Contingency: If a label schema mismatch reaches production, the OrgLabelsProvider fallback mechanism ensures users see a reasonable English default rather than a raw key. A backend label patch can be deployed without an app release.