high priority medium complexity frontend pending frontend specialist Tier 5

Acceptance Criteria

After dialog confirmation (task-007), the Cubit emits MultiOrgSwitching state and calls TenantContextService.switchTenant(orgId)
A loading indicator is shown in the switcher UI while the swap is in progress (blocks further interaction)
On success, the modal bottom sheet is dismissed programmatically
After sheet dismissal, the active org indicator in the app bar or settings menu updates to show the new org's name and branding (logo/colors if applicable) without requiring a full app restart
After sheet dismissal, GoRouter navigates to the role-appropriate home screen for the new tenant context
On failure, the Cubit emits MultiOrgSwitchError state, restores the previously active org as the highlighted selection in the switcher, and shows an inline error message with a retry option
The previous active org is preserved in Cubit state so rollback is possible without a network call
All state transitions (idle → switching → success/error → idle) are driven exclusively by the Cubit — no setState in the widget
The app-bar/settings active org indicator is driven by a separate app-level Cubit (e.g., ActiveTenantCubit) that is updated on successful swap
Widget test verifies loading state blocks interaction, success closes sheet and updates active org indicator, failure restores previous selection

Technical Requirements

frameworks
Flutter
flutter_bloc
go_router
apis
TenantContextService.switchTenant(orgId) → Future<TenantSwitchResult>
ActiveTenantCubit.updateActiveTenant(org) — app-level state update
UserRoleService.getRoleForTenant(orgId) — to determine navigation target
data models
TenantContext
OrgMembership
UserRole
TenantSwitchResult
performance requirements
Tenant switch operation must complete within 3 seconds on a standard connection — show loading if it exceeds 500ms
App bar update must reflect the new org within one frame of successful switch — no polling
security requirements
TenantContextService.switchTenant() must re-validate the user's membership server-side before completing the swap
All cached data from the previous tenant context (contacts, activities, etc.) must be invalidated or cleared on successful swap to prevent data leakage between orgs
The new tenant's auth token/session scope must be applied to all subsequent API calls immediately after the swap
ui components
Loading overlay within the MultiOrgContextSwitcher sheet (CircularProgressIndicator with AbsorbPointer)
ActiveTenantIndicator widget in AppBar/settings menu (reads from ActiveTenantCubit)
Inline error banner within the switcher sheet on failure

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

The MultiOrgContextSwitcherCubit should hold previousActiveOrgId in its state so rollback on error requires no additional API call. Use a BlocListener in the MultiOrgContextSwitcher widget to react to success/error states: on success, call Navigator.of(context).pop() to close the sheet, then use a callback or event bus to update ActiveTenantCubit at the app level, then navigate via GoRouter. Avoid calling GoRouter inside the bottom sheet's context — instead, pass a VoidCallback onSwitchSuccess to the sheet widget, or use a stream/event bus listened to at the root Navigator level. For cache invalidation, trigger a global ClearTenantDataEvent on the relevant repository Cubits after a successful switch — define a common interface or use an event bus (e.g., a stream exposed by TenantContextService).

ActiveTenantCubit should be provided at the MaterialApp level so the AppBar can rebuild reactively. Apply design tokens for branding updates (org accent color) via the ActiveTenantCubit state, not by directly manipulating ThemeData at runtime.

Testing Requirements

Write Cubit unit tests: (1) emits [switching, switchSuccess] on successful TenantContextService call, (2) emits [switching, switchError] with previousActiveOrgId preserved on failure, (3) ActiveTenantCubit is notified on success. Write widget tests: (4) loading overlay blocks interaction during switch, (5) sheet is dismissed on success, (6) ActiveTenantIndicator in app bar reflects new org after success, (7) failure shows inline error and restores previous active org highlight in list, (8) retry on failure re-dispatches ConfirmOrgSwitch. Integration test: simulate a full switch flow from tap → dialog confirm → loading → success → home screen navigation. Use flutter_test, bloc_test, and mock TenantContextService.

Epic Risks (2)
low impact high prob technical

OrgSelectionScreen and OrgContextSwitcher render partner-specific logos, colors, and text from dynamic data. Golden tests (pixel-comparison screenshots) will fail whenever branding assets are updated in the backend, causing CI failures that block unrelated PRs and eroding developer trust in the test suite.

Mitigation & Contingency

Mitigation: Use fixture-based golden tests with static mock Organization models containing embedded test assets rather than network-fetched assets. Separate branding asset acceptance tests into a dedicated CI job that only runs on branding-related PRs and is maintained by the design team.

Contingency: If golden test maintenance overhead becomes excessive, replace pixel-comparison goldens with semantic widget tests that assert widget tree structure and key property values, reserving golden tests for only the most stable, design-critical elements.

high impact medium prob scope

Several partner organizations (especially Blindeforbundet) have users who rely entirely on VoiceOver or TalkBack. Complex branded card layouts with overlaid logos, names, and selection states are notoriously difficult to make fully accessible; missing semantics or incorrect focus order could make the selection screen completely unusable for screen reader users before launch.

Mitigation & Contingency

Mitigation: Involve an accessibility specialist in the design review before any widget implementation begins. Use Flutter's Semantics widget with explicit label, hint, and button role on OrgCardWidget. Conduct manual screen reader testing on both iOS (VoiceOver) and Android (TalkBack) for every sprint that touches these screens, not just before release.

Contingency: If full WCAG compliance cannot be achieved within the sprint, implement a simplified text-list fallback mode that activates when the system detects an active screen reader, presenting orgs as plain accessible list tiles instead of the branded card layout.