high priority low complexity frontend pending frontend specialist Tier 0

Acceptance Criteria

QrCodeGenerator is a StatelessWidget in lib/features/recruitment/presentation/widgets/ accepting required String data and double size, with optional QrErrorCorrectLevel errorCorrectionLevel (default: QrErrorCorrectLevel.M), Color foregroundColor (default: Colors.black), Color backgroundColor (default: Colors.white)
When data is non-empty, the widget renders a QR code using the qr_flutter QrImageView widget with the provided parameters
When data is empty or blank, the widget renders a placeholder container of the specified size with a centered icon (e.g., Icons.qr_code) and no QR image, without throwing an exception
The rendered widget is wrapped in a Semantics widget with a meaningful label (e.g., 'QR code for referral link') and excludeSemantics: true on the inner QrImageView to prevent duplicate announcements
generateBytes(String data, double size) is a static method that returns a Uint8List PNG representation of the QR code using qr_flutter's QrPainter.toImageData; it throws ArgumentError if data is empty
foregroundColor and backgroundColor are correctly applied to the QR code rendering (module color and background color)
Widget is covered by golden tests at 200×200, 300×300, and 400×400 sizes to detect rendering regressions
Widget does not import any Supabase or business-logic code — it is purely presentational
The widget respects the project's design token system for any non-QR UI elements (placeholder state)

Technical Requirements

frameworks
Flutter
qr_flutter (QrImageView, QrPainter, QrErrorCorrectLevel)
performance requirements
Widget must render synchronously (no async operations in build method); generateBytes may be async
QR image generation for a standard referral URL (< 200 characters) must complete in < 100 ms on a mid-range device
security requirements
The data string passed to the QR generator must be URL-encoded before rendering to prevent malformed QR codes
generateBytes must not cache results in memory beyond the immediate call to avoid stale QR images after code rotation
ui components
QrImageView (qr_flutter)
Semantics
placeholder Container with Icons.qr_code

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Use QrImageView for the rendered widget (handles its own canvas) and QrPainter directly for generateBytes (paint to ui.Image, then toByteData). Be aware that QrPainter requires a version parameter — pass QrVersions.auto and let the library pick the minimum version for the data length. For generateBytes, run inside a compute isolate if called frequently to avoid blocking the UI thread, though for one-off share operations synchronous execution is acceptable. Keep the widget file small (< 80 lines) — resist adding business logic.

Document the generateBytes method with a dartdoc comment explaining it is intended for share-sheet usage only.

Testing Requirements

Widget tests using flutter_test: (1) renders QrImageView when data is non-empty; (2) renders placeholder when data is empty string; (3) renders placeholder when data is whitespace-only; (4) Semantics label is present and correct; (5) foregroundColor and backgroundColor are passed through to QrImageView. Unit test for generateBytes: (1) returns non-empty Uint8List for valid data; (2) throws ArgumentError for empty data; (3) output is valid PNG bytes (check magic bytes FF D8 or 89 50 4E 47). Golden tests at three sizes to catch rendering regressions. Run with `flutter test --update-goldens` when intentional changes are made.

Component
QR Code Generator
infrastructure low
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.