Declare terminologySyncServiceProvider and wire disposal
epic-dynamic-terminology-and-labels-service-layer-task-009 — Declare the terminologySyncServiceProvider in TerminologyRiverpodProviders as an autoDispose provider that creates, starts, and disposes TerminologySyncService. Wire provider disposal on logout by invalidating the provider when auth state transitions to unauthenticated. Ensure the sync service provider reads organizationLabelsNotifierProvider's ref to trigger reloads without circular dependencies.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 3 - 413 tasks
Can start after Tier 2 completes
Implementation Notes
Pattern: use `ref.listen(authStateProvider, (prev, next) { if (next.isUnauthenticated) ref.invalidateSelf(); })` inside the provider create callback to wire logout invalidation without creating a separate side-effect provider. To avoid circular deps, pass `ref.read(organizationLabelsNotifierProvider.notifier)` as a constructor argument to TerminologySyncService at creation time rather than having the sync service read the provider itself. Use `ref.onDispose(() => service.dispose())` for cleanup. Consider wrapping the whole create body in a try/catch to ensure ref.onDispose is always registered even if service construction throws.
Testing Requirements
Unit tests using ProviderContainer: (1) verify service is started on provider creation; (2) verify service dispose is called when provider is disposed; (3) verify provider invalidation fires when auth state emits unauthenticated; (4) verify a new service instance is created after re-listen post-logout; (5) verify no circular dependency by inspecting the provider graph — use ProviderContainer.read() in topological order; (6) verify that disposing mid-sync does not throw. Use a fake/mock AuthStateStream and a mock TerminologySyncService to control timing. Integration test: simulate full login → sync → logout → re-login cycle and assert service lifecycle events in order.
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.
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.
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.