high priority low complexity backend pending backend specialist Tier 1

Acceptance Criteria

ActivitySummaryAggregator exposes an abstract interface IActivitySummaryAggregator with at minimum an aggregate({required String mentorId, DateTimeRange? dateRange}) async method returning ActivitySummary
ActivitySummary contains: sessionCount (int), totalDurationMinutes (double), averageDurationMinutes (double), sessionsWithoutDuration (int)
aggregation query filters activity records by mentorId and status = 'completed' at minimum
When dateRange is provided, only activities with a start_time within the range are included
Activities with null duration are counted in sessionCount and sessionsWithoutDuration but excluded from duration calculations
Empty result set returns ActivitySummary with all numeric fields set to 0 without throwing
Supabase query uses server-side aggregation (count, sum) rather than fetching all rows client-side — verified by checking query structure
Service contains no direct UI dependencies and no BLoC/Cubit imports
Registered in Riverpod provider layer for injection into BenefitCalculationService
Handles the real-world case documented in requirements (a peer mentor with 380 registrations in one year) without performance degradation

Technical Requirements

frameworks
Flutter
Riverpod
Supabase Flutter SDK
apis
Supabase PostgREST — activity_logs or activities table with count/sum aggregation
data models
ActivitySummary
ActivityRecord
performance requirements
Aggregation query completes in under 500ms for up to 500 activity records
Use Supabase server-side aggregation (select count(*), sum(duration_minutes)) rather than client-side reduce to minimize data transfer
Query must use an index on (mentor_id, status, start_time) — document the required index in a migration comment
security requirements
Supabase RLS must restrict activity access so a peer mentor can only query their own records
mentorId parameter must come from the authenticated session, never from unvalidated user input
Date range inputs must be validated: endDate >= startDate, dates must be reasonable (not far future)

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Use Supabase's .rpc() or aggregate query pattern for server-side count/sum. If the Supabase table doesn't yet support direct aggregation via PostgREST, consider a Postgres function (RPC) that accepts mentor_id, start_date, end_date and returns {session_count, total_duration_minutes} — this is the most performant approach and avoids fetching 380 rows. Define the abstract interface IActivitySummaryAggregator so the BenefitCalculationService can be tested independently. Place the service at lib/features/benefit_calculator/services/activity_summary_aggregator.dart.

For the DateTimeRange parameter, use Flutter's DateTimeRange from dart:ui or define a project-local equivalent to avoid Flutter dependency in pure-logic layers. Document the required database index (CREATE INDEX idx_activities_mentor_status_time ON activities(mentor_id, status, start_time)) in a comment or migration file.

Testing Requirements

Unit tests using flutter_test and mocktail covering: correct aggregation from a multi-row mock result, empty result handling, date range filter forwarding, partial data (null duration) handling, and verification that no direct Supabase call exists in the service class (architecture boundary test). Integration test (optional, CI-gated) verifying correct Supabase query structure and aggregation against a test database. Aim for 90%+ branch coverage.

Component
Benefit Calculator Screen
ui low
Epic Risks (3)
high impact medium prob technical

The RepaintBoundary PNG capture approach for sharing the results card may produce blurry or oversized images on high-DPI devices, or may silently fail on certain Android OEM configurations that restrict off-screen rendering. A failed share would break one of the core use cases (recruitment tool).

Mitigation & Contingency

Mitigation: Implement the capture using the established screenshot-capture-utility pattern already present in the Wrapped summary feature (component 542-screenshot-capture-utility). Test on a range of iOS and Android devices including Samsung and Huawei OEM builds during development. Set explicit pixel ratio (3.0) when calling toImage() to guarantee resolution.

Contingency: If image capture fails on a platform, the BenefitShareService falls back to sharing the plain-text summary only, with a user-facing message explaining the image could not be generated. This ensures the share flow never fully blocks.

high impact medium prob technical

Implementing full WCAG 2.2 AA compliance for the results card and metric tiles — including live regions, focus management, and semantic labels that read naturally in Norwegian — requires deep familiarity with Flutter semantics APIs. Gaps may only surface during screen reader testing on physical devices, late in the sprint.

Mitigation & Contingency

Mitigation: Use the existing semantics-wrapper-widget (606) and live-region-announcer (608) components from the accessibility feature rather than implementing custom semantics. Assign screen reader testing on a physical iPhone with VoiceOver as a mandatory acceptance gate, not an afterthought. Write widget tests using Flutter's AccessibilityGuideline matchers early in development.

Contingency: If screen reader issues are found late, the pure semantic markup approach (no Canvas numbers, all Semantics wrappers) limits the blast radius to label text corrections. Escalate to the accessibility feature team for a pairing session to resolve complex focus management issues.

medium impact low prob integration

The BenefitResultsCard must match the Wrapped design language used in the annual summary feature. If design tokens or widget patterns are inconsistent between the two features, the results card will look out of place and undermine the intended emotional impact for sharing.

Mitigation & Contingency

Mitigation: Review the existing Wrapped summary screen (529-wrapped-summary-screen) and stat card widget (530-stat-card-widget) implementations before building the results card. Reuse design tokens from the existing design-token-theme (200) system. Involve the designer in a review of the results card mock-up against the Wrapped language before implementation begins.

Contingency: If design parity issues are discovered post-implementation, isolate visual adjustments to the BenefitResultsCard widget. The feature's business logic and accessibility compliance are unaffected by visual polish changes.