high priority medium complexity backend pending backend specialist Tier 2

Acceptance Criteria

buildDeepLinkUri(context) returns a valid go_router URI string that includes activityId, contactId, activityType, prefillDate, and prefillDuration as route parameters or query parameters
The generated URI targets the activity registration wizard route and is accepted by the router without a 'route not found' error
prefillDate is encoded as an ISO 8601 UTC string in the URI; prefillDuration is encoded as integer minutes
buildDeepLinkUri() is a pure synchronous function — it does not call any repository or Supabase function
navigateToWizard(context, router) calls router.go() (not router.push()) to replace the navigation stack, preventing the user from back-navigating to the notification handler
Warm-start path: when the app is in the foreground or background, navigateToWizard() navigates immediately without waiting for app initialization
Cold-start path: when the app launches from a terminated state due to a notification tap, the deep link URI is stored and consumed after the app's initialization sequence (auth, Supabase connection) completes
Cold-start handling uses a pending deep link queue (max 1 item) that is consumed exactly once by the post-init lifecycle hook
ScenarioDeepLinkHandler exposes a Riverpod provider that can be watched by the app root widget to consume pending deep links on initialization
All URI components are properly URL-encoded; special characters in activityType do not break the URI structure

Technical Requirements

frameworks
Flutter
go_router
Riverpod
flutter_test
apis
go_router GoRouter API
Flutter AppLifecycleListener
data models
ScenarioContext
PendingDeepLink (activityId, contactId, activityType, prefillDate, prefillDuration, createdAt)
performance requirements
buildDeepLinkUri() must execute in under 1ms (pure string construction)
navigateToWizard() warm-start navigation must complete the router.go() call within one frame (16ms)
security requirements
URI parameters must not include sensitive user data beyond IDs; no names, addresses, or health information in the URI string
Cold-start pending deep link must be cleared from memory immediately after consumption — do not persist to SharedPreferences or local storage
activityId and contactId in the URI will be re-validated server-side in task-008; the handler itself should not be considered a security boundary

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Implement ScenarioDeepLinkHandler as a Riverpod StateNotifier or plain Provider class. Keep buildDeepLinkUri() strictly pure — it should be a static method or a method with no instance state. For the cold-start flow, maintain a StateProvider called pendingScenarioDeepLinkProvider. The app root widget (or the auth gate widget) should watch this provider and call navigateToWizard() then set the state back to null.

This avoids platform channel complexity and works reliably with go_router. Encode the URI using Uri(path: ..., queryParameters: {...}).toString() to ensure correct percent-encoding. Use the route path string constants defined in the existing go_router configuration — do not hardcode path strings in this handler. Document the cold-start lifecycle clearly: push notification received → app launched → pendingDeepLink stored → app init (Supabase auth) completes → root widget consumes pending link → navigateToWizard() called.

Testing Requirements

Write unit tests using flutter_test for buildDeepLinkUri(): verify URI structure for standard inputs, verify ISO 8601 date encoding, verify URL encoding of special characters in activityType, verify all five context fields appear in the output. For navigateToWizard(): use a GoRouter mock to verify router.go() is called with the correct URI. Write widget tests for the cold-start path: simulate app termination state by calling the pending deep link store before initialization, then trigger the post-init hook and assert the router mock received the correct navigation call. Test that a second cold-start deep link overwrites the first (max 1 pending item).

Test that the pending link is null after consumption.

Component
Scenario Deep Link Handler
service medium
Epic Risks (2)
high impact medium prob scope

The Rule Engine must support a flexible JSON rule schema that can express compound conditions (e.g., contact_type AND wellbeing_flag AND delay_days). Underestimating schema expressiveness may require breaking changes to the rule format after coordinators have already configured rules.

Mitigation & Contingency

Mitigation: Define and freeze the rule JSON schema (trigger_type enum, metadata_conditions structure, delay logic) before any implementation begins; validate schema against all known HLF scenarios documented in the feature spec.

Contingency: If schema changes are needed after deployment, implement a schema version field and a migration utility that upgrades stored rules to the new format without coordinator intervention.

medium impact medium prob technical

Deep-link navigation to the activity wizard with pre-filled arguments may fail if the user's session has expired or if the wizard route is not yet mounted in the navigator stack, causing unhandled navigation exceptions.

Mitigation & Contingency

Mitigation: Implement session state check before navigation; if session is expired, redirect to biometric/login screen and store the pending deep-link URI for post-auth redirect using go_router's redirect mechanism.

Contingency: If post-auth redirect proves unreliable, fall back to navigating to the home screen with a visible action banner that re-triggers the wizard with pre-filled arguments.