high priority low complexity testing pending testing specialist Tier 8

Acceptance Criteria

Authenticating as a global admin user results in the No-Access Screen being displayed as the root route — no home screen, no bottom navigation tabs visible
Route guard intercepts all direct navigation attempts (including deep links) and redirects to No-Access Screen when user role is global_admin
The admin portal link on No-Access Screen is tappable and opens the correct external URL (verified via url_launcher mock in test)
No tab bar, floating action button, or any app content from normal roles is rendered when No-Access Screen is active
Screen reader semantics on No-Access Screen: heading node present with role 'header', body text node present, admin portal link has descriptive label and is identified as a link
Deep link to any app route (e.g., /contacts, /home) while authenticated as global admin routes to No-Access Screen, not the target route
All test cases pass on both iOS and Android integration test targets

Technical Requirements

frameworks
Flutter
flutter_test
BLoC
apis
Supabase Auth (mocked)
url_launcher (mocked)
data models
UserRole
UserSession
performance requirements
No-Access Screen must render within 300ms of route guard firing in test environment
security requirements
Test must assert that zero app-data widgets (contacts list, home content, work tab) are present in the widget tree when No-Access Screen is active
Global admin role must never gain access to any app content route — this must be a hard block, not a soft redirect
ui components
No-Access Screen
Route Guard
Admin portal link button

Execution Context

Execution Tier
Tier 8

Tier 8 - 48 tasks

Can start after Tier 7 completes

Implementation Notes

Keep this test suite focused and lean — the global admin block is a hard security boundary, so the tests should be simple and unambiguous. Use a dedicated test user with role = 'global_admin' only (no secondary roles). The route guard check should happen at the top-level router redirect, not inside individual screen widgets — verify that the guard is implemented at the router level so deep links are caught before any screen builds. For the admin portal link: use a MockUrlLauncher or dependency-inject the launcher so tests do not require network.

Semantic validation here is important because Blindeforbundet users (screen reader dependent) may encounter this screen if they are ever assigned a global admin role by mistake — the screen must be fully navigable by assistive technology.

Testing Requirements

Use Flutter integration_test package with a seeded global_admin user fixture (separate from multi-role fixture used in task-013). Test cases: (1) direct login → No-Access Screen render assertion, (2) deep link to /home → redirect to No-Access Screen, (3) deep link to /contacts → redirect to No-Access Screen, (4) admin portal link tap → url_launcher mock receives correct URL, (5) semantics tree inspection on No-Access Screen using tester.getSemantics(). For deep link tests, use GoRouter's test helpers to simulate incoming deep links. Mock url_launcher to avoid actually opening a browser during CI.

Assert widget absence for BottomNavigationBar and HomeScreen using findsNothing matchers.

Component
No-Access Screen
ui low
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.