high priority medium complexity testing pending testing specialist Tier 3

Acceptance Criteria

Test file exists at test/features/recruitment/infrastructure/recruitment_attribution_repository_test.dart
Test: recordEvent succeeds for each value in the AttributionEventType enum (link_click, registration, conversion — or as defined) without throwing
Test: recordEvent maps a PostgrestException to a domain NetworkException for network failures
Test: getConversionFunnel returns a ConversionFunnelStats object with correct clickCount, registerCount, and convertCount populated from mocked aggregation response
Test: getConversionFunnel returns zeros for all counts when the Supabase response is an empty list
Test: getMentorConversionStats returns results ordered by conversion rate descending (assert on the order of the returned list)
Test: getMentorConversionStats returns an empty list when no mentors have attribution data
Test: a Supabase RLS-denied error (HTTP 403 or PostgrestException with code 42501) when querying outside org is mapped to an UnauthorisedException domain error
Test: recordEvent with a null or empty referral code string throws an ArgumentError before any Supabase call is made (input validation guard)
All tests pass with flutter test, zero warnings, ≥90% branch coverage on recruitment_attribution_repository.dart

Technical Requirements

frameworks
flutter_test
mocktail or mockito
supabase_flutter
apis
Supabase PostgREST client (mocked)
Supabase RLS error codes (42501 / HTTP 403)
data models
RecruitmentAttributionEvent
AttributionEventType (enum)
ConversionFunnelStats
MentorConversionStat
performance requirements
All tests must complete within 3 seconds — no real I/O
security requirements
RLS boundary test must assert that the repository surfaces a typed UnauthorisedException — not a raw Supabase error — so UI layers can handle it without knowledge of Supabase internals
Test fixture data must not use real organisation or member IDs

Execution Context

Execution Tier
Tier 3

Tier 3 - 413 tasks

Can start after Tier 2 completes

Implementation Notes

The most complex test is getMentorConversionStats ordering — if the ordering is performed in Dart (not delegated to SQL ORDER BY), stub the Supabase response with unordered data and assert the method sorts correctly. If ordering is delegated to Supabase, stub the response as already-ordered and assert the method does not re-sort. Document which approach is used so tests align with implementation. For the conversion funnel aggregation, the mocked Supabase response shape must match what the actual Supabase RPC or grouped query returns — inspect the real query's response format first.

Use a test helper factory (e.g. makeAttributionEvent({...})) to reduce boilerplate across the many event_type enum tests. Consider parameterised tests using a loop over AttributionEventType.values to keep the enum coverage tests concise.

Testing Requirements

Use flutter_test with mocktail. Structure tests in group() blocks per repository method. The RLS test is the highest-value test in this suite — ensure it covers the scenario where Supabase returns a PostgrestException with statusCode 403 or pgcode 42501, and that the repository re-throws a domain UnauthorisedException. For the ordering test on getMentorConversionStats, provide mock data with three mentors at deliberately different conversion rates and assert the returned list is sorted highest-first.

Use setUp() and tearDown() for mock lifecycle management. Generate coverage with 'flutter test --coverage' — target ≥90% branch coverage on the repository file. Do not use real Supabase connections.

Component
Recruitment Attribution Repository
data medium
Epic Risks (3)
high impact medium prob technical

iOS Universal Links and Android App Links have distinct configuration requirements (apple-app-site-association, assetlinks.json, entitlements). A misconfiguration causes the OS to open the referral URL in a browser instead of the app, completely breaking the onboarding funnel for new members on one platform.

Mitigation & Contingency

Mitigation: Configure both Universal Links and App Links from the start of this epic using the project's existing Supabase-hosted domain. Write an E2E test on both simulators that taps a referral URL and asserts the onboarding screen is reached. Document the required server-side JSON files alongside the migration.

Contingency: If platform deep-link configuration cannot be resolved before the UI epics need the handler, implement a fallback custom-scheme URI (e.g., likeperson://referral?code=XYZ) that works unconditionally, and schedule Universal/App Link fix as a follow-up task.

high impact high prob security

Referral click events must be writable without an authenticated session (a new member who has not yet registered is tapping the link). Standard Supabase RLS cannot grant anonymous inserts without opening a security hole. If this is not solved early it blocks the entire attribution pipeline.

Mitigation & Contingency

Mitigation: Design referral_events writes to go exclusively through a Supabase Edge Function that validates the referral code exists and is active before inserting. The Edge Function uses the service-role key server-side; the client only calls the function endpoint. This is documented in the feature spec.

Contingency: If the Edge Function approach is delayed, temporarily allow anon inserts restricted by a CHECK constraint that event_type = 'click' and new_member_id IS NULL, then tighten to Edge Function writes in a follow-up migration before the feature goes to production.

medium impact low prob dependency

The qr_flutter package version pinned in pubspec may conflict with the current Flutter SDK version or with other packages in the monorepo, causing build failures that block QR code delivery.

Mitigation & Contingency

Mitigation: Verify qr_flutter compatibility against the project's Flutter SDK version as the very first task in this epic. If a conflict exists, resolve it before any other work proceeds.

Contingency: If qr_flutter cannot be made compatible, evaluate mobile_scanner (already likely in pubspec for QR scanning) which also supports generation, or implement QR generation via a lightweight Dart port as a last resort.