high priority medium complexity frontend pending frontend specialist Tier 1

Acceptance Criteria

CoordinatorHomeContent renders activity overview summary cards showing: total activities this month, total hours this month, and number of unique peer mentors active
A prominent quick-action button is visible above the fold to start a new activity registration — tapping it navigates to the Activity Wizard
Pending attestation indicator displays count of activities awaiting coordinator attestation; shows zero-state text when count is 0
Coordinator statistics snapshot shows this week vs. last week comparison for activities and hours
All data is loaded via the coordinator's scoped Supabase queries (filtered by org_id and coordinator's assigned area)
When the user switches away from coordinator role and back, content fully refreshes — stale data from the previous session is not shown
Loading state shows skeleton placeholders (not spinner) for each card region
Error state shows a friendly retry card if data fetch fails — does not crash or show raw error text
All text elements meet WCAG 2.2 AA contrast ratio (4.5:1 for normal text, 3:1 for large text) against the design token background colors
Screen reader announces card headings and numeric values in logical reading order

Technical Requirements

frameworks
Flutter
BLoC
Riverpod
apis
Supabase PostgREST — activities table (coordinator-scoped)
Supabase PostgREST — user_roles/attestations table
data models
Activity
Attestation
CoordinatorStats
UserRole
performance requirements
Initial data load completes and skeleton resolves within 2 seconds on 4G connection
Role-switch content refresh completes within 1 second
security requirements
All Supabase queries must include org_id and coordinator_id filters — Row Level Security enforces this server-side but queries must also scope client-side for defense in depth
Numeric statistics must never show data from outside the coordinator's assigned org/area
ui components
CoordinatorHomeContent (this widget)
StatSummaryCard (reusable stat card with value + label + trend indicator)
QuickActionButton (prominent CTA using AppButton variant)
AttestationIndicatorBadge
SkeletonCard (loading placeholder)

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Implement CoordinatorHomeContent as a ConsumerWidget (Riverpod) or BlocBuilder subscriber. Create a CoordinatorHomeCubit or CoordinatorHomeNotifier that fetches data on initialization and exposes a refresh() method. Use AsyncValue (Riverpod) or distinct Loading/Loaded/Error states (BLoC) — do not store raw Future in widget state. For the statistics snapshot, a single Supabase RPC or aggregation query is preferable over multiple round trips.

Use design tokens for all colors and typography — do not hardcode hex values. The skeleton loading pattern should match the final card layout exactly to prevent layout shift when data loads. Refer to the existing reusable widgets (AppButton, page header) documented in the architecture for consistent UI patterns.

Testing Requirements

Widget tests for CoordinatorHomeContent using flutter_test. Mock the data provider/BLoC to return: (a) loaded state with sample data, (b) loading state, (c) error state. Assert correct widget tree for each state. Verify navigation: tap quick-action button and assert NavigatorObserver.didPush is called with the Activity Wizard route.

Verify role-switch refresh: simulate a role state change to peerMentor and back to coordinator, assert that a new data fetch is triggered (provider/BLoC rebuild). Accessibility test: use flutter_test semantics API to assert that all Semantics nodes have non-empty labels.

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.