high priority low complexity frontend pending frontend specialist Tier 0

Acceptance Criteria

RecruitmentStatsWidget is a StatelessWidget that renders three stat values: total shares, confirmed conversions, and pending signups
Widget consumes a Riverpod FutureProvider or StreamProvider wrapping ReferralAttributionService data
Loading state renders skeleton placeholders (shimmer or progress indicator) in place of stat values
Empty state renders a non-error message (e.g., 'No recruitment activity yet') when all stats are zero
Error state renders a retry action with a descriptive message
All stat labels and values use design token typography (no hardcoded font sizes or colors)
Stat value color uses the design token accent color for numeric values for visual emphasis
Widget is fully self-contained — it manages its own provider subscription internally
All text elements have Semantics labels appropriate for screen readers (e.g., '3 confirmed conversions')
Widget renders correctly at all standard Flutter screen widths (360dp to 428dp) without overflow

Technical Requirements

frameworks
Flutter
Riverpod
apis
ReferralAttributionService (internal Riverpod provider)
Supabase PostgreSQL 15 (via service layer)
data models
assignment
contact
performance requirements
Provider fetch completes within 2 seconds on a standard mobile connection
Widget does not trigger unnecessary rebuilds — provider should be keyed to the authenticated mentor's ID
security requirements
Stats data fetched via RLS-enforced Supabase query — mentor sees only their own referral attribution data
No raw contact data exposed in stats widget — only aggregated counts
ui components
Row or GridView of stat cards (3 columns)
Text (stat value, large bold design token style)
Text (stat label, small secondary design token style)
CircularProgressIndicator or shimmer placeholder (loading state)
EmptyStateWidget (zero state)
ErrorRetryWidget (error state)

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Define a `RecruitmentStatsData` freezed/immutable class with `totalShares`, `confirmedConversions`, and `pendingSignups` int fields. The Riverpod provider should be a `FutureProvider.autoDispose.family(mentorId)`. Use `ref.watch` inside the widget's build method. For the stat card layout, a `Row` with three `Expanded` children works well at fixed widths.

Apply `Theme.of(context).textTheme.headlineMedium` for stat values and `textTheme.labelSmall` for labels — map these to your design token theme. Use `AsyncValue.when` for state handling.

Testing Requirements

Write widget tests using flutter_test with ProviderScope overrides. Test (1) three stat values render correctly with mock provider data, (2) loading skeleton renders when provider is AsyncLoading, (3) empty state message renders when all stats are zero, (4) error state with retry renders when provider is AsyncError, (5) Semantics tree includes labels for all stat values. Verify design token colors are applied by checking widget tree for correct TextStyle references. Run golden tests for loading, empty, data, and error states.

Component
Recruitment Stats Widget
ui low
Epic Risks (3)
medium impact medium prob technical

QR codes rendered at the minimum 200×200 size may fail to scan under typical indoor lighting conditions on older or lower-resolution phone cameras, causing recruitment moments to fail when a peer mentor shows the screen to a prospective member.

Mitigation & Contingency

Mitigation: Set the default QR render size to 260×260 logical pixels (not the 200px minimum) and apply a high-contrast white module background. Test scan reliability on at minimum three physical devices (budget Android, mid-range Android, iPhone SE) before marking the screen as done.

Contingency: If scan reliability remains an issue, add a 'Enlarge QR' full-screen mode triggered by tapping the code, and ensure the text referral URL with copy-to-clipboard is always visible as a fallback sharing method.

high impact medium prob integration

The onboarding screen submits attribution and then hands off to an external membership registration URL (HLF's Dynamics portal or similar). If the external URL is unavailable, changes its format, or requires authentication the new member does not have, the conversion funnel is broken at its final step.

Mitigation & Contingency

Mitigation: Confirm the external registration URL and its expected query parameters with HLF's portal team before implementing the handoff. Record the pending_signup attribution event before launching the URL so data is not lost if the external site fails. Display a fallback message with contact information if the URL launch fails.

Contingency: If the external membership URL is not available at feature launch, implement a temporary form that collects name and email and stores a pending_member record in Supabase, allowing coordinators to manually complete registration while the integration is finalised.

low impact medium prob integration

Embedding the RecruitmentStatsWidget on the peer mentor home screen may conflict with existing layout components (activity summary, badge shelf), causing overflow or requiring a redesign of the home screen that is outside this epic's scope.

Mitigation & Contingency

Mitigation: Design the widget as a horizontally constrained card with a maximum height of 96dp so it can be inserted into any vertical list without overflow. Coordinate with the home screen's existing layout owners before starting the embedding task.

Contingency: If home screen embedding creates unacceptable layout conflicts, defer embedding to a separate home-screen redesign task and make the widget accessible only via the dedicated ReferralCodeScreen for the initial release.