Wire CTA deep link from Notification Card
epic-scenario-based-follow-up-prompts-scheduler-and-ui-task-007 — Implement the CTA tap handler in ScenarioPromptNotificationCard that constructs and fires a deep link to the activity wizard pre-populated with the triggering activity's peer mentor and scenario context. Use the Scenario Deep Link Handler to resolve the route and pass required parameters via GoRouter.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 6 - 158 tasks
Can start after Tier 5 completes
Implementation Notes
Inject GoRouter via context.go() using the standard go_router BuildContext extension — do not store a GoRouter reference in the widget. Pass onTap callback from parent to keep the card widget testable without a full routing environment: ScenarioPromptNotificationCard(onCtaTap: () => handler.navigate(context, notification)). Implement debounce with a bool _navigating flag set on first tap and reset after navigation or 1 second timeout. ScenarioDeepLinkHandler.resolve(scenarioId) should return a named GoRouter route string like '/activity/new?peerId=...&scenarioId=...&activityId=...'.
For the activity wizard pre-population, the wizard should read these params from GoRouterState.uri.queryParameters in its build method and initialize the relevant BLoC/Riverpod state. Mark notification as read by calling ref.read(notificationRepositoryProvider).markRead(notification.id) in the tap handler — not in didChangeDependencies.
Testing Requirements
Widget tests with flutter_test and GoRouter test helpers (GoRouter.setLogging, MockGoRouter or RoutingConfig). Test cases: (1) tap CTA — assert GoRouter.go called with path containing scenarioId and activityId as query params; (2) ScenarioDeepLinkHandler returns null — assert fallback route called (e.g. '/activity/new'), no exception; (3) double-tap — assert GoRouter.go called exactly once (debounce); (4) after tap, assert notification read-state provider updated to isRead=true; (5) verify peerId and scenarioId in route params are valid UUID format via regex assertion in test. Integration test: use Flutter integration_test package to tap card in full app, assert activity wizard screen title is visible and peer mentor field is pre-filled.
If the scheduler runs concurrently (e.g., two overlapping cron invocations due to edge function retry), duplicate prompts could be dispatched before the first run's history records are committed, breaking the deduplication guarantee.
Mitigation & Contingency
Mitigation: Use a Postgres advisory lock or unique constraint on (user_id, scenario_id, activity_ref) in the prompt history table to make concurrent writes idempotent; design the scheduler to check history inside a transaction.
Contingency: If concurrency issues persist in production, add a distributed lock via Supabase Edge Function concurrency limit (max_instances=1) for the evaluation function as a hard guard.
Coordinators may find scenario configuration unclear if trigger conditions are expressed as raw JSON or technical terminology, leading to misconfiguration and irrelevant prompts being sent to peer mentors.
Mitigation & Contingency
Mitigation: Design the ScenarioConfigurationScreen to display human-readable descriptions of each template's trigger condition (e.g., 'Send 3 days after first contact if wellbeing concern was flagged') rather than raw rule properties; validate with an HLF coordinator in a design review before implementation.
Contingency: If coordinators still misconfigure rules after launch, add a preview mode that shows a simulated prompt based on a test activity before the rule is enabled.