medium priority medium complexity frontend pending frontend specialist Tier 3

Acceptance Criteria

MentorReferralDetailScreen accepts mentorId (String) and dateRange (DateTimeRange) as required route arguments
Screen title displays the mentor's display name (fetched or passed as argument), not their internal ID
Breadcrumb renders 'Dashboard > [Mentor Name]' and back navigation returns to recruitment dashboard without triggering a data reload
Referral events list renders events in reverse chronological order (newest first) with: event type badge (issued/clicked/registered), event timestamp (formatted as local date + time), and where applicable the referral link identifier
Event type badges use unified entity color system: issued = primary, clicked = secondary, registered = success accent
Screen shows loading indicator while ReferralAttributionService fetch is in progress
Empty state is shown when no events exist for the mentor in the selected date range, with a descriptive message including the date range
Error state is shown on fetch failure with a retry button
Active date range is displayed as a subtitle below the screen title (e.g. 'Last 30 days')
Screen is accessible: event rows have Semantics labels combining event type, timestamp, and any link info
Screen renders correctly for mentors with 0, 1, and 50+ events (no overflow, no jank)
Widget tests cover loading, loaded (with events), empty, and error states

Technical Requirements

frameworks
Flutter
BLoC (flutter_bloc) or Riverpod
go_router for route arguments
apis
ReferralAttributionService (internal)
Supabase PostgreSQL 15 via service layer
data models
assignment
contact
activity
performance requirements
List must use ListView.builder for efficient rendering of large event lists
Initial data fetch must complete within 2 seconds on a standard mobile connection
security requirements
Route arguments must be validated on screen init — reject navigation with missing or malformed mentorId
Data fetched must be scoped to coordinator's organization_id from auth context — never trust mentorId alone without org scoping
RLS enforced server-side; screen must not display data if fetch returns permission error — show error state instead
ui components
MentorReferralDetailScreen (new screen widget)
ReferralEventRow (row widget per event)
EventTypeBadge (colored badge for issued/clicked/registered)
AppBreadcrumb (reuse existing breadcrumb pattern)
AppPageHeader with subtitle
AppEmptyState
AppErrorRetry

Execution Context

Execution Tier
Tier 3

Tier 3 - 413 tasks

Can start after Tier 2 completes

Implementation Notes

Pass mentorId and dateRange as typed route arguments via go_router's extra parameter or encoded as query params — prefer typed extra to avoid string encoding complexity. Do not re-fetch the mentor's display name from Supabase if it can be passed as a route argument from the dashboard row (where it was already loaded) — this avoids an extra network round-trip. Implement a dedicated MentorReferralDetailBloc or Cubit for this screen's loading state, keeping it separate from the dashboard BLoC. Dispose the local BLoC when the screen is popped.

For the breadcrumb, reuse the existing AppBreadcrumb widget if available; if not, a simple Row with TextButton + Text is acceptable. Format timestamps using intl package DateFormat with locale awareness.

Testing Requirements

Widget tests (flutter_test): (1) screen renders mentor name in title when loaded, (2) events list is in reverse chronological order for a fixture with 3 events at known timestamps, (3) empty state renders with date range label when event list is empty, (4) error state renders retry button, (5) tapping retry dispatches reload, (6) back navigation pops the route. Mock ReferralAttributionService using mocktail. Integration test: verify navigation from dashboard mentor row to detail screen passes correct arguments (can be a navigator test without a real backend).

Component
Coordinator Recruitment Dashboard
ui medium
Epic Risks (3)
medium impact high prob dependency

BadgeCriteriaIntegration must reference specific badge definition IDs from the badge-definition-repository for recruitment badges. If those badge definitions have not been created in the database when this epic is implemented, the integration will silently fail to award badges.

Mitigation & Contingency

Mitigation: As the first task of this epic, create the four recruitment badge definitions (seed data migration) with known, stable IDs. BadgeCriteriaIntegration hardcodes these IDs as constants. Include an assertion in the integration tests that verifies the badge definition records exist in the test database.

Contingency: If the badge definitions system does not support seeding at migration time, store the badge definition IDs in a feature-flag-style config table and look them up at runtime, falling back to a no-op with a warning log if they are absent.

medium impact medium prob technical

The coordinator dashboard aggregates referral stats across all peer mentors in an organisation. For large organisations (HLF has many peer mentors nationally), the aggregation query may be slow, causing the dashboard to feel unresponsive.

Mitigation & Contingency

Mitigation: Implement the aggregation as a Supabase database view or RPC that runs server-side with appropriate indexes on (mentor_id, org_id, created_at, event_type). Add a composite index on referral_events during the foundation epic's migration. Cache the result in the Riverpod provider with a 5-minute TTL.

Contingency: If query performance remains unacceptable at scale, materialise the aggregation in a nightly pg_cron job into a stats_cache table, and serve the dashboard from the cache with a 'last updated' timestamp shown to the coordinator.

medium impact low prob integration

The existing badge award service is implemented by the achievement-badges feature. If that feature's public API (BadgeAwardService interface) changes while this epic is in progress, the BadgeCriteriaIntegration will break at compile time or behave incorrectly at runtime.

Mitigation & Contingency

Mitigation: Confirm the BadgeAwardService interface is stable and document the exact method signatures this integration depends on. Write a narrow integration test that constructs the real BadgeAwardService against a test database to detect breaking changes immediately.

Contingency: If the badge service interface changes, adapt the BadgeCriteriaIntegration adapter class to match the new contract. The adapter pattern used here isolates the change to a single class.