critical priority low complexity infrastructure pending infrastructure specialist Tier 1

Acceptance Criteria

AndroidManifest.xml contains an intent filter for the referral URI scheme with actions VIEW and BROWSABLE, scheme and host correctly set, and pathPattern or pathPrefix covering the referral token path
iOS Info.plist contains a CFBundleURLSchemes entry for the custom URI scheme and an Associated Domains entitlement entry (applinks:<domain>) for Universal Links
apple-app-site-association (AASA) file is hosted at https://<domain>/.well-known/apple-app-site-association with correct appID, paths, and content-type application/json
Cold-start scenario: launching the app via a referral deep link from a closed state routes to the new-member onboarding screen with the correct token extracted
Foreground-resume scenario: tapping a referral link while the app is backgrounded routes correctly without restarting the Flutter engine
Supabase project's redirect URL allow-list includes all referral deep-link URI patterns (custom scheme and Universal Link domain)
Apple Developer portal has Associated Domains capability enabled for the app bundle ID
Google Play Console has app link verification passing for the deep-link domain (if App Links / Digital Asset Links are used)
A runbook document is committed to the repo under docs/ listing all portal configuration steps, allow-list entries, and AASA hosting requirements
No existing URI schemes or intent filters are broken by the new additions

Technical Requirements

frameworks
Flutter
flutter_applinks or app_links package (platform channel bridge)
GoRouter (existing app router)
apis
Supabase redirect URL allow-list API / dashboard configuration
Apple Developer portal Associated Domains API
Google Play Console Digital Asset Links verification
data models
ReferralCode (token extracted from URI path/query)
DeepLinkPayload (scheme, host, path, queryParameters)
performance requirements
Deep-link resolution must complete within 500 ms of app launch (cold-start)
AASA file must be served with HTTP 200 and without redirects to satisfy Apple CDN cache requirements
security requirements
AASA file must be served over HTTPS only — HTTP is rejected by iOS
Intent filter must NOT use android:autoVerify=false; use App Links verification to prevent URI hijacking
Token extracted from the URI must be treated as untrusted input — validation occurs in DeepLinkHandler, not in manifest parsing
Supabase allow-list entries must be as specific as possible (no wildcard * patterns) to prevent open-redirect vulnerabilities

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Use the app_links Flutter package (pub.dev) as the platform-channel bridge — it supports both custom schemes and App Links/Universal Links uniformly and is actively maintained. For the AASA file, ensure it is served by the same CDN/host as the deep-link domain with no redirects; Apple's CDN caches AASA aggressively, so changes may take up to 24 h to propagate. On Android, set android:autoVerify="true" on the intent filter and ensure the Digital Asset Links JSON file is hosted at https:///.well-known/assetlinks.json with the correct package name and SHA-256 fingerprint. The Supabase allow-list must include both the production and staging variants of the deep-link URI.

Commit an .env.example or README section listing every external configuration step so future engineers and CI pipelines can reproduce the setup. Keep the intent filter path pattern narrow (e.g. /referral/* only) to avoid the app claiming unrelated links.

Testing Requirements

Manual device testing is the primary verification method for this infrastructure task. Test on a physical iOS device (iOS 16+) and Android device (API 31+) as simulators/emulators do not fully replicate Universal Link and App Link verification. Test matrix: (1) cold-start via Safari/Chrome tap on Universal Link, (2) cold-start via custom URI scheme from Notes app, (3) foreground-resume from Safari, (4) foreground-resume via ADB am start on Android, (5) unrecognised path does not route to onboarding. Automated integration test coverage is handled in task-012.

Confirm aasa-validator or branch.io AASA checker passes for the hosted file. Run 'adb shell pm verify-links' to confirm Android App Link verification status.

Component
Deep Link / OAuth Redirect Handler
infrastructure 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.