critical priority low complexity infrastructure pending backend specialist Tier 3

Acceptance Criteria

labelProvider(String key) is declared as a Riverpod family provider in TerminologyRiverpodProviders and compiles without errors
Watching labelProvider('greeting') does NOT trigger a rebuild when an unrelated label (e.g., 'submit_button') changes in the underlying map
When organizationLabelsNotifierProvider is in loading state, labelProvider(key) returns the raw key string as fallback
When organizationLabelsNotifierProvider is in loaded state and the key is absent from the map, labelProvider(key) returns the raw key string as fallback
When organizationLabelsNotifierProvider is in loaded state and the key is present, labelProvider(key) returns the resolved label string
When organizationLabelsNotifierProvider is in error state, labelProvider(key) returns the raw key string as fallback (no exception propagated to the widget)
The provider uses select() or equivalent mechanism to avoid subscribing to the full label map state object
labelProvider family instances are auto-disposed or shared as appropriate — no unbounded memory growth across org switches
All fallback paths log a debug trace (not error) so missing keys are discoverable during development

Technical Requirements

frameworks
Flutter
Riverpod
data models
OrganizationLabelsState
TerminologyLabelsMap
performance requirements
Widget rebuild scope limited to the single watched key — verified via flutter_test ProviderContainer listener counts
Provider resolution must complete synchronously when the labels map is already loaded (no additional async hop)
Family provider instances must not leak across organization switches — container dispose must clean up all family instances
security requirements
Fallback to raw key must never expose internal state or stack traces to the UI layer

Execution Context

Execution Tier
Tier 3

Tier 3 - 413 tasks

Can start after Tier 2 completes

Implementation Notes

Use Riverpod's `select` operator on the family provider to subscribe only to the slice of state relevant to the given key: `ref.watch(organizationLabelsNotifierProvider.select((state) => state.whenData((map) => map[key] ?? key).valueOrNull ?? key))`. Handle all three AsyncValue variants (loading, error, data) in the select lambda to ensure the fallback contract is met without conditionals scattered across the codebase.

Prefer `autoDispose` on the family provider to prevent memory accumulation when many keys are watched across different screens. Document the fallback behavior contract clearly in a doc comment on the provider declaration so consumers understand the 'raw key on miss' semantic.

Testing Requirements

Unit tests using flutter_test and ProviderContainer: (1) verify labelProvider returns resolved value when map is loaded and key is present; (2) verify raw key fallback when map is loading; (3) verify raw key fallback when key is absent from loaded map; (4) verify raw key fallback when notifier is in error state; (5) verify granular rebuild — set up two listeners on different keys, mutate only one key in the map, assert only the corresponding listener fires; (6) verify no leak after container.dispose(). All tests use mock/fake OrganizationLabelsNotifier to control state transitions deterministically.

Component
Terminology Riverpod Providers
infrastructure low
Epic Risks (3)
high impact medium prob technical

When a user switches organization context (e.g., a coordinator with multi-org access), a race condition between the outgoing organization's map disposal and the incoming organization's fetch could briefly expose the wrong organization's terminology to the widget tree.

Mitigation & Contingency

Mitigation: Implement an explicit loading state in OrganizationLabelsNotifier that widgets check before rendering any resolved labels. The provider graph should cancel the previous organization's fetch via Riverpod's ref.onDispose before initiating the next.

Contingency: If the race manifests in production, fall back to English defaults during the transition window and emit a Sentry error event for investigation; the UX impact is a brief English flash rather than wrong-org terminology.

high impact low prob security

Supabase Row Level Security policies on organization_configs may inadvertently restrict the authenticated user from reading their own organization's labels JSONB column, causing silent empty maps that appear as English fallbacks.

Mitigation & Contingency

Mitigation: Write and test explicit RLS policies that grant SELECT on the labels column to any authenticated user whose organization_id matches. Add an integration test that verifies label fetch succeeds for each role (peer mentor, coordinator, admin).

Contingency: If RLS blocks are discovered in production, temporarily escalate label fetch to a service-role edge function while the RLS policy is corrected, ensuring no labels are exposed cross-organization.

medium impact medium prob scope

A peer mentor who installs the app for the first time with no internet connection will have no cached terminology map and will see only English defaults, which may be confusing for organizations like NHF that use Norwegian-specific role names exclusively.

Mitigation & Contingency

Mitigation: Bundle a default fallback terminology map for each known organization as a compile-time asset (Dart asset file) so that even fresh installs without connectivity render correct organizational terminology immediately.

Contingency: If bundled assets are out of date, display a one-time informational banner noting that terminology will update on next connectivity restore, with no functional blocking of the app.