critical priority medium complexity frontend pending frontend specialist Tier 0

Acceptance Criteria

RoleBasedHomeScreen renders the correct content variant immediately on first frame based on the current RoleState — no flash of wrong content
When RoleStateManager emits a new role (e.g., user switches context via Role Switch Widget), the home screen transitions to the new variant within one frame without full widget rebuild of the scaffold
Coordinator state renders CoordinatorHomeContent; peerMentor state renders PeerMentorHomeContent; orgAdmin state renders OrgAdminHomeContent; globalAdmin/blocked state redirects to NoAccessScreen
unauthenticated state redirects to the auth flow — no home screen content is shown
Widget subscribes to RoleStateManager via BLoC BlocBuilder or Riverpod Consumer — no manual StreamSubscription in State objects
RoleBasedHomeScreen passes a11y audit: all interactive elements have semantic labels, role announcements fire on variant switch for screen reader users
Widget tree is navigable via keyboard/switch access in correct tab order
Variant switching animation (if any) respects the system-level Reduce Motion setting

Technical Requirements

frameworks
Flutter
BLoC
Riverpod
data models
RoleState
UserRole
performance requirements
First meaningful paint of role-specific content within 100ms of screen push
Role variant switch completes within a single frame (16ms budget)
security requirements
globalAdmin role must never render any home content — always redirect to NoAccessScreen
unauthenticated state must always redirect to auth — no partial home content leakage
ui components
RoleBasedHomeScreen (scaffold widget)
CoordinatorHomeContent (slot placeholder — implemented in task-002)
PeerMentorHomeContent (slot placeholder — implemented in task-003)
OrgAdminHomeContent (slot placeholder — implemented in task-004)
NoAccessScreen redirect (implemented in task-005)

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Implement RoleBasedHomeScreen as a stateless widget wrapping a BlocBuilder (or Riverpod Consumer watching roleStateProvider). Use a switch expression on RoleState to return the appropriate child widget — avoid nested if-else chains. Define CoordinatorHomeContent, PeerMentorHomeContent, and OrgAdminHomeContent as separate widget files even if they are empty placeholder containers at this stage — this prevents circular dependencies when child tasks implement them. For the redirect cases (globalAdmin, unauthenticated), use WidgetsBinding.instance.addPostFrameCallback to push the redirect route after the frame completes rather than redirecting inside build(), which can cause build-phase navigation errors.

Follow the existing AppButton and page header reusable widget patterns from the shared component library.

Testing Requirements

Widget tests using flutter_test. Test each RoleState → rendered variant mapping using pumpWidget with a mocked/fake RoleStateManager providing a controlled stream. Assert correct widget type is present in the tree for each state using find.byType. Test role switch: pump initial state, emit new role state, call pumpAndSettle, assert new variant.

Test redirect behavior for globalAdmin and unauthenticated states using a NavigatorObserver mock. Aim for 100% branch coverage of the role-dispatch switch/if logic.

Component
Role-Based Home Screen
ui medium
Epic Risks (3)
high impact medium prob technical

Combining GoRouter's declarative redirect logic in the route guard with StatefulShellRoute's stateful branch management is known to produce subtle bugs where the shell rebuilds unnecessarily on role switches, losing tab state or causing double-navigation events.

Mitigation & Contingency

Mitigation: Implement the route guard as a GoRouter redirect callback that only evaluates role from an already-resolved Riverpod provider (not async). Use a dedicated ShellRoute navigator key per tab branch to anchor state independently of role-driven rebuilds. Write integration tests for the full navigation graph.

Contingency: If StatefulShellRoute state loss is confirmed during QA, fall back to a manual tab state preservation approach using a TabStateManager service that caches the last route per tab and restores it after role switches, decoupling tab state from the shell lifecycle.

medium impact high prob scope

The role-based home screen must render three significantly different layouts (coordinator dashboard, peer mentor activity summary, org admin overview). If these variants are implemented as a single widget with conditionals, the file will become unmaintainable and difficult to test in isolation, especially as each variant grows with downstream feature additions.

Mitigation & Contingency

Mitigation: Design the role-based home screen as a router/dispatcher widget that delegates to three separate variant widgets (CoordinatorHomeView, PeerMentorHomeView, OrgAdminHomeView). Each variant is independently testable and can be developed by separate team members in parallel.

Contingency: If variant coupling has already occurred before this risk is addressed, refactor to the dispatcher pattern in a dedicated cleanup task before feature handoff. The dispatcher pattern is a straightforward extraction that carries low refactoring risk.

medium impact medium prob integration

The no-access screen must link global admin users to the correct admin portal URL, which may differ per organization (NHF, HLF, Blindeforbundet each have their own admin portals). Hardcoding a single URL will result in wrong or broken links for some global admin users.

Mitigation & Contingency

Mitigation: Source the admin portal URL from the organization's configuration record in Supabase rather than hardcoding it. The no-access screen reads the active org context and resolves the portal URL dynamically. Provide a safe fallback to a generic Norse Digital Products support page if the URL is not configured.

Contingency: If dynamic URL resolution is not ready when the no-access screen ships, display a static instruction to contact the organization's administrator along with a support email address as an interim measure, and track the URL configuration task as a follow-up.