high priority medium complexity frontend pending frontend specialist Tier 7

Acceptance Criteria

A Riverpod FutureProvider (or AutoDisposeFutureProvider) named activityContextProvider is defined, scoped by activity ID, and fetches full activity data from the Activity repository
The Detail Sheet shows a skeleton/shimmer loading state while the FutureProvider is in loading state — no blank white flash
On successful load, peer mentor name is displayed using the correct name field from the Activity and related assignment/contact entities
Activity date is formatted according to Norwegian locale (dd.MM.yyyy) using intl package or equivalent
Activity duration is displayed in hours and minutes (e.g., '1 t 30 min') derived from the duration field on the Activity entity
Notes snippet shows the first 150 characters of the activity notes field with a '...' ellipsis if truncated
Wellbeing flags from the Activity entity are passed to the WellbeingFlagChip widgets already scaffolded in task-008
On error state, a user-friendly error message is shown with a retry button that re-triggers the FutureProvider
Provider is properly auto-disposed when the sheet is closed — no memory leaks
Accessibility: loading state announces 'Loading activity details' to screen readers; content change announces new content on load completion
If the activity has no notes, the notes section is hidden entirely (not shown as empty)
Data fetched uses the activity_id provided through the ScenarioPrompt model — no hardcoded IDs

Technical Requirements

frameworks
Flutter
Riverpod
apis
Supabase PostgreSQL 15
data models
activity
assignment
contact
performance requirements
Activity data fetch must complete within 2 seconds on a 4G connection
Provider caches result for the lifetime of the sheet — no refetch on sheet scroll
Notes field truncated client-side to 150 chars — do not fetch entire document for snippet
security requirements
Activity fetch must use the authenticated Supabase client — no unauthenticated access
RLS on the activities table ensures coordinator can only fetch activities within their chapter — verify this at the Supabase policy level, not in Flutter code
Peer mentor PII (full name) must not be logged to console or crash reporters
ui components
Shimmer/skeleton loading state widgets
Error state widget with retry button using AppButton
FormattedDateText widget (or intl DateFormat usage)
DurationDisplay widget showing hours/minutes
NotesSnippet text widget with ellipsis overflow
WellbeingFlagChip (from task-008)

Execution Context

Execution Tier
Tier 7

Tier 7 - 84 tasks

Can start after Tier 6 completes

Implementation Notes

Create a dedicated ActivityContextProvider using riverpod's FutureProvider.autoDispose.family(activityId). Define an ActivityContext value object with the fields needed by the sheet (peerMentorName, date, durationMinutes, notesSnippet, wellbeingFlags) — do not pass the raw Activity model directly into UI. This value object acts as a view model and insulates the UI from database schema changes. For duration formatting, create a pure function formatDuration(int minutes) -> String that handles edge cases.

Locale-aware date formatting should use intl's DateFormat('dd.MM.yyyy') — confirm the intl package is already a dependency before adding. For the loading state, use a Column of shimmer Container placeholders matching the approximate layout of the loaded state. Follow the existing Riverpod provider naming conventions in the codebase. Do not use .watch inside initState — use ConsumerWidget or ConsumerStatefulWidget pattern.

Testing Requirements

Write widget tests and unit tests using flutter_test. Unit test 1: activityContextProvider returns correct ActivityContext model when repository returns valid data. Unit test 2: Duration formatting helper converts raw minutes to '1 t 30 min' format correctly including edge cases (0 min, 60 min exactly, 90 min). Widget test 1: Sheet shows skeleton widgets when FutureProvider is in loading state.

Widget test 2: Sheet shows correct peer mentor name, date, and duration on success state. Widget test 3: Sheet shows error widget with retry on FutureProvider error state. Widget test 4: Notes section hidden when notes field is null or empty. Widget test 5: Provider auto-disposes when sheet is removed from widget tree (verify with ProviderContainer).

Mock the Activity repository using Mockito or manual stubs — do not call Supabase in widget tests.

Epic Risks (2)
high impact medium prob technical

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.

medium impact medium prob scope

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.