critical priority low complexity database pending database specialist Tier 0

Acceptance Criteria

ActivitySummary is an immutable Dart class with fields: sessionCount (int), averageDurationMinutes (double), totalDurationMinutes (double), periodStart (DateTime), periodEnd (DateTime).
ActivitySummary.empty() factory returns a zero-value instance suitable for pre-populated calculator display before any data is loaded.
copyWith(), ==, hashCode, and toString() are implemented.
toJson() and fromJson() handle DateTime serialization as ISO-8601 strings.
A DateRange value class is defined with start (DateTime) and end (DateTime) and used as the parameter type in the repository interface.
abstract class IActivitySummaryRepository is defined in a separate file with a single method: Future<ActivitySummary> getActivitySummaryForMentor(String mentorId, DateRange dateRange).
The interface file has no imports from Supabase or any infrastructure package — only Dart core and the model files.
Unit tests confirm: ActivitySummary.empty() produces all-zero values, toJson/fromJson round-trip, DateRange correct construction.
Files are placed in the domain layer (lib/features/benefit_calculator/domain/) to enforce clean architecture separation.

Technical Requirements

frameworks
Flutter
flutter_test
data models
ActivitySummary
DateRange
performance requirements
Model construction and serialization under 1ms.
security requirements
mentorId in the interface signature is a UUID string — ensure it is validated as non-empty before use in implementations.
No PII stored in ActivitySummary — only aggregate numeric values and date boundaries.

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Place ActivitySummary and DateRange in lib/features/benefit_calculator/domain/models/. Place IActivitySummaryRepository in lib/features/benefit_calculator/domain/repositories/. Use DateTime.toIso8601String() for toJson and DateTime.parse() for fromJson. The averageDurationMinutes field must be consistent with totalDurationMinutes / sessionCount — document this invariant but do not enforce it in the model (the aggregator service is responsible for correctness).

The DateRange class should validate that end is not before start in its constructor to catch configuration errors early. Keep the interface minimal — a single method — to preserve the interface segregation principle.

Testing Requirements

Unit tests in test/models/activity_summary_test.dart. Cover: construction, empty() factory produces zeros and valid DateTimes, copyWith partial override, equality, toJson produces ISO-8601 strings for DateTime fields, fromJson parses ISO-8601 back to DateTime correctly, fromJson with invalid date string throws FormatException. Separately verify DateRange construction. No integration tests for this task.

Component
Activity Summary Aggregator
service low
Epic Risks (2)
medium impact medium prob integration

Supabase organisation configuration table may not yet have the five multiplier columns, requiring a migration. If the migration is not coordinated with other teams touching the same table, schema conflicts could delay delivery.

Mitigation & Contingency

Mitigation: Add multiplier columns in a dedicated, non-destructive ALTER TABLE migration script. Review the organisation config table schema with the backend team before writing the migration. Use nullable columns with defaults so existing rows are unaffected.

Contingency: If the migration cannot be deployed in time, stub the repository to return hardcoded default multiplier values from a local config file, allowing parallel development. Swap in the real Supabase fetch once the migration is live.

low impact medium prob scope

The ActivitySummaryAggregator depends on activity records already persisted in the database. For newly onboarded peer mentors with no activity history, the aggregator will return zero counts, which could make the calculator appear broken on first use.

Mitigation & Contingency

Mitigation: Design the pre-fill value object to distinguish between 'no data yet' and 'zero activities'. The calculator input panel should display empty inputs (not zero) when no history exists, with placeholder text guiding the user to enter values manually.

Contingency: If the distinction cannot be surfaced cleanly in the UI timeline, fall back to always showing empty inputs and document the manual-entry path as the primary UX until activity data accumulates.